#!/bin/sh PROGNAME="$0" usage() { cat < /dev/null geo-html2gpx *.html > found.gpx EOF exit 1 } # # Report an error and exit # error() { echo "`basename $PROGNAME`: $1" >&2 exit 1 } debug() { if [ $DEBUG -ge $1 ]; then echo "`basename $PROGNAME`: $2" >&2 fi } if [ `uname` = 'Darwin' ]; then awk=gawk date=gdate else awk=awk date=date fi # # Read RC file, if there is one # USERNAME= if [ -f $HOME/.georc ]; then . $HOME/.georc # N.B. must switch to read_rc_file if LAT/LON is ever needed here fi # # Process the options # POSTPROC="cat" DEBUG=0 INCR=0 NOWPTS=0 NOZERO=0 NOHTML=0 DECODE=1 NUMLOGS=1000000 while getopts "beE:iwzl:no:u:D:h?" opt do case $opt in b) POSTPROC="gpsbabel -igpx -f- -ogpx -F-";; e) DECODE=0;; E) eval "$OPTARG";; i) INCR=1;; l) NUMLOGS="$OPTARG";; o) POSTPROC="gpsbabel -igpx -f- -o$OPTARG -F-";; n) NOHTML=1;; u) USERNAME="$OPTARG";; w) NOWPTS=1;; z) NOZERO=1;; D) DEBUG="$OPTARG";; h|\?) usage;; esac done shift `expr $OPTIND - 1` # # Main Program # YR=`date +"%Y"` case `$awk --version` in "GNU Awk"*) ;; *) error "awk is not GNU awk!";; esac cat "$@" \ | tr -d '\001\002\003\004\005\006\007\015\021\022\023\024\026\030' \ | sed 's/ 0) rv = rv * 16 + (k-1) else break; } return rv } function prsJSON_EncodeAsUTF8( v, s, p1, p2, p3, p4, cs ) { cs = "\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377" if ( v < 128 ) s = sprintf("%c", v ) else if ( v < 2048 ) # 110xxxxx 10xxxxxx { p1 = int(v/64) % 32 p2 = v % 64 s = substr(cs, 65+p1, 1) substr(cs, p2+1, 1) } else if ( v < 65536 ) # 1110xxxx 10xxxxxx 10xxxxxx { p1 = int(v/4096) % 16 p2 = int(v/64) % 64 p3 = v % 64 s = substr(cs, 97+p1, 1) substr(cs, p2+1, 1) substr(cs, p3+1, 1) } else if ( v < 1114112 ) # 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx { p1 = int(v/262144) % 8 p2 = int(v/4096) % 64 p3 = int(v/64) % 64 p4 = v % 64 s = substr(cs, 113+p1, 1) substr(cs, p2+1, 1) substr(cs, p3+1, 1) substr(cs, p4+1, 1) } else s = "" return s; } function prsJSON_UnescapeString(jsonString, matchedString, matchedValue) { if (jsonString == "\"\"") return "" if (jsonString ~ /^".+"$/) jsonString = substr(jsonString,2,length(jsonString)-2) gsub(/\\\\/, "\\u005C", jsonString) gsub(/\\"/, "\"", jsonString) gsub(/\\\//, "/", jsonString) gsub(/\\b/, "\b", jsonString) gsub(/\\f/, "\f", jsonString) gsub(/\\n/, "\n", jsonString) gsub(/\\r/, "\r", jsonString) gsub(/\\t/, "\t", jsonString) if (match(jsonString, /\\[^u]/)) return "ParseJSON Error: Invalid String at " jsonString # handle encoded UTF-16 surrogates while (match(jsonString, /\\uD[89AaBb][0123456789AaBbCcDdEeFf][0123456789AaBbCcDdEeFf]\\uD[CcDdEeFf][0123456789AaBbCcDdEeFf][0123456789AaBbCcDdEeFf]/)) { matchedValue = (prsJSON_hex2num(substr(jsonString, RSTART+2, 4)) % 1024) * 1024 + prsJSON_hex2num(substr(jsonString, RSTART+8, 4)) % 1024 + 65536 #print matchedValue, substr(jsonString, RSTART+2, 4), substr(jsonString, RSTART+8, 4) matchedString = prsJSON_EncodeAsUTF8( matchedValue ) sub(/\\uD[89AaBb][0123456789AaBbCcDdEeFf][0123456789AaBbCcDdEeFf]\\uD[CcDdEeFf][0123456789AaBbCcDdEeFf][0123456789AaBbCcDdEeFf]/, matchedString, jsonString) } while (match(jsonString, /\\u[0123456789AaBbCcDdEeFf][0123456789AaBbCcDdEeFf][0123456789AaBbCcDdEeFf][0123456789AaBbCcDdEeFf]/)) { matchedValue = prsJSON_hex2num(substr(jsonString, RSTART+2, 4)) matchedString = prsJSON_EncodeAsUTF8( matchedValue ) sub(/\\u[0123456789AaBbCcDdEeFf][0123456789AaBbCcDdEeFf][0123456789AaBbCcDdEeFf][0123456789AaBbCcDdEeFf]/, matchedString, jsonString) } return jsonString; } function prsJSON_ValidString(jsonString) { return jsonString !~ /^ParseJSON Error: Invalid String at / } function prsJSON_SetDataValue(jsonData, prefix, value) { jsonData[prefix] = value } function prsJSON_Error(jsonStringArr, cnt, idx, jsonData, message) { split("", jsonData) prsJSON_SetDataValue(jsonData, "1", sprintf("ParseJSON Error: %s at ", message) (idx <= cnt ? jsonStringArr[idx] : "")) split("", jsonStringArr) return cnt + 1 } function prsJSON_CopyError(jsonData, tv) { split("", jsonData) prsJSON_SetDataValue(jsonData, "1", tv[1]) } function prsJSON_ParseNumber(jsonStringArr, cnt, idx, jsonData, prefix) { if (idx <= cnt) { if (match(jsonStringArr[idx], /^(\-?)(0|[123456789][0123456789]*)(\.[0123456789]+)?([eE][+-]?[0123456789]+)?/)) { prsJSON_SetDataValue(jsonData, prefix, substr(jsonStringArr[idx], 1, RLENGTH)) jsonStringArr[idx] = length(jsonStringArr[idx]) >= RLENGTH+1 ? substr(jsonStringArr[idx], RLENGTH+1) : "" } else idx = prsJSON_Error(jsonStringArr, cnt, idx, jsonData, "Number not found") # starts like a number, but doesnt match the REGEX } return idx } function prsJSON_ParseString(jsonStringArr, cnt, idx, jsonData, prefix, jsonString, idxn, idxs, idxq, t) { if (idx <= cnt && length(jsonStringArr[idx]) > 0 && substr(jsonStringArr[idx], 1, 1) == "\"") { idxn = 2 jsonString = jsonStringArr[idx] do { t = length(jsonString) >= idxn ? substr(jsonString, idxn) : "" idxs = index(t, "\\") idxq = index(t, "\"") # no valid close quote found if (idxq == 0) { if (idx == cnt) break; idx++ jsonString = jsonString "," jsonStringArr[idx] } # a valid close quote was found - not before a slash if (idxq != 0 && (idxs == 0 || (idxs != 0 && idxq < idxs))) break; if (idxs != 0 && idxq == idxs + 1) # slash quote idxn = idxn + idxq else idxn = idxn + idxs + 1 } while (1) if (idxq > 0) { t = substr(jsonString, 1, idxn+idxq-1) if (match(t, /[\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037]/) == 0) { t = prsJSON_UnescapeString(t) if ( prsJSON_ValidString(t) ) { prsJSON_SetDataValue(jsonData, prefix, t) jsonStringArr[idx] = length(jsonString) >= idxn+idxq ? substr(jsonString,idxn+idxq) : "" } else idx = prsJSON_Error(jsonStringArr, cnt, idx, jsonData, "Invalid string") } else idx = prsJSON_Error(jsonStringArr, cnt, idx, jsonData, "Invalid character in string") } else idx = prsJSON_Error(jsonStringArr, cnt, idx, jsonData, "Unterminated string") } else idx = prsJSON_Error(jsonStringArr, cnt, idx, jsonData, "String expected") return idx } function prsJSON_ParseObject(jsonStringArr, cnt, idx, jsonData, prefix, tv ) { if (idx <= cnt) { sub(/^\{[ \t\r\n\f]*/, "", jsonStringArr[idx]) #skip open { and skipwhite while (idx <= cnt && length(jsonStringArr[idx]) > 0 && substr(jsonStringArr[idx], 1, 1) != "}") { idx = prsJSON_ParseString(jsonStringArr, cnt, idx, tv, "1") if (idx <= cnt && length(tv[1]) == 0) idx = prsJSON_Error(jsonStringArr, cnt, idx, tv, "Empty string used for property name") if (idx <= cnt) { sub(/^[ \t\r\n\f]+/, "", jsonStringArr[idx]) #skipwhite if ( length(jsonStringArr[idx]) > 0 && substr(jsonStringArr[idx], 1, 1) == ":" ) { sub(/^:[ \t\r\n\f]*/, "", jsonStringArr[idx]) #skip colon and skipwhite if ( length(jsonStringArr[idx]) > 0 ) { idx = prsJSON_ParseJSONInt(jsonStringArr, cnt, idx, jsonData, prefix != "" ? prefix SUBSEP tv[1] : tv[1]) if (idx <= cnt) { sub(/^[ \t\r\n\f]+/, "", jsonStringArr[idx]) #skipwhite if (length(jsonStringArr[idx]) == 0 && idx < cnt) { idx++ sub(/^[ \t\r\n\f]+/, "", jsonStringArr[idx]) #skipwhite if (length(jsonStringArr[idx]) == 0 || substr(jsonStringArr[idx], 1, 1) == "}") idx = prsJSON_Error(jsonStringArr, cnt, idx, jsonData, "Expected object property") } else if (length(jsonStringArr[idx]) == 0 || substr(jsonStringArr[idx], 1, 1) != "}") idx = prsJSON_Error(jsonStringArr, cnt, idx, jsonData, "Expected object property or closing brace") } } else idx = prsJSON_Error(jsonStringArr, cnt, idx, jsonData, "Expected JSON value (1)") } else idx = prsJSON_Error(jsonStringArr, cnt, idx, jsonData, "Expected colon") } else prsJSON_CopyError(jsonData, tv) } if (idx <= cnt && (length(jsonStringArr[idx]) == 0 || substr(jsonStringArr[idx], 1, 1) != "}")) idx = prsJSON_Error(jsonStringArr, cnt, idx, jsonData, "Expected closing brace") if (idx <= cnt && length(jsonStringArr[idx]) > 0 && substr(jsonStringArr[idx], 1, 1) == "}") sub(/^\}[ \t\r\n\f]*/, "", jsonStringArr[idx]) #skip close } and skipwhite } return idx } function prsJSON_ParseArray(jsonStringArr, cnt, idx, jsonData, prefix, ii) { if (idx <= cnt) { sub(/^\[[ \t\r\n\f]*/, "", jsonStringArr[idx]) #skip open bracket and skipwhite ii = 1 while (idx <= cnt && length(jsonStringArr[idx]) > 0 && substr(jsonStringArr[idx], 1, 1) != "]") { idx = prsJSON_ParseJSONInt(jsonStringArr, cnt, idx, jsonData, prefix != "" ? prefix SUBSEP ii : ii ) ii++ if (idx <= cnt) { sub(/^[ \t\r\n\f]+/, "", jsonStringArr[idx]) #skipwhite if (length(jsonStringArr[idx]) == 0 && idx < cnt) { idx++; sub(/^[ \t\r\n\f]+/, "", jsonStringArr[idx]) #skipwhite if (length(jsonStringArr[idx]) == 0 || substr(jsonStringArr[idx], 1, 1) == "]") idx = prsJSON_Error(jsonStringArr, cnt, idx, jsonData, "Expected array value") } else if (length(jsonStringArr[idx]) == 0 || substr(jsonStringArr[idx], 1, 1) != "]") idx = prsJSON_Error(jsonStringArr, cnt, idx, jsonData, "Expected array value or closing bracket") } } if (idx <= cnt && (length(jsonStringArr[idx]) == 0 || substr(jsonStringArr[idx], 1, 1) != "]")) idx = prsJSON_Error(jsonStringArr, cnt, idx, jsonData, "Expected closing bracket") if (idx <= cnt && length(jsonStringArr[idx]) > 0 && substr(jsonStringArr[idx], 1, 1) == "]") sub(/^\][ \t\r\n\f]*/, "", jsonStringArr[idx]) #skip close bracket and skipwhite } return idx } function prsJSON_ParseJSONInt(jsonStringArr, cnt, idx, jsonData, prefix, tk) { if (idx <= cnt) { sub(/^[ \t\r\n\f]+/, "", jsonStringArr[idx]) #skipwhite if (length(jsonStringArr[idx]) > 0) { tk = substr(jsonStringArr[idx], 1, 1) if (tk == "\"" && prefix != "") idx = prsJSON_ParseString(jsonStringArr, cnt, idx, jsonData, prefix) else if (tk ~ /^[0123456789-]/ && prefix != "") idx = prsJSON_ParseNumber(jsonStringArr, cnt, idx, jsonData, prefix) else if (jsonStringArr[idx] ~ /^true/ && prefix != "") { prsJSON_SetDataValue(jsonData, prefix, "<>") jsonStringArr[idx] = length(jsonStringArr[idx]) <= 4 ? "" : substr(jsonStringArr[idx],5) } else if (jsonStringArr[idx] ~ /^false/ && prefix != "") { prsJSON_SetDataValue(jsonData, prefix, "<>") jsonStringArr[idx] = length(jsonStringArr[idx]) <= 5 ? "" : substr(jsonStringArr[idx],6) } else if (jsonStringArr[idx] ~ /^null/ && prefix != "") { prsJSON_SetDataValue(jsonData, prefix, "<>") jsonStringArr[idx] = length(jsonStringArr[idx]) <= 4 ? "" : substr(jsonStringArr[idx],5) } else if (tk == "{") idx = prsJSON_ParseObject(jsonStringArr, cnt, idx, jsonData, prefix) else if (tk == "[") idx = prsJSON_ParseArray(jsonStringArr, cnt, idx, jsonData, prefix) else idx = prsJSON_Error(jsonStringArr, cnt, idx, jsonData, "Expected JSON value (2)") if (idx <= cnt) sub(/^[ \t\r\n\f]+/, "", jsonStringArr[idx]) #skipwhite } if (prefix == "" && idx <= cnt && length(jsonStringArr[idx]) != 0) idx = prsJSON_Error(jsonStringArr, cnt, idx, jsonData, "Expected end of JSON text") else if (prefix == "" && idx+1 <= cnt) { idx++ idx = prsJSON_Error(jsonStringArr, cnt, idx, jsonData, "Expected end of JSON text (2)") } } return idx } # # JSON Formatting Routines # function useJSON_ArrayCount( possibleArray, a, min, max, cnt, rv) { cnt = 0 for ( a in possibleArray ) { if (possibleArray[a] "" !~ /^[0123456789][0123456789]*$/) return -1 if ( cnt == 0 ) { min = possibleArray[a] max = possibleArray[a] } else { if (min == possibleArray[a] || max == possibleArray[a]) return -1 if (possibleArray[a] < min) min = possibleArray[a] if (max < possibleArray[a]) max = possibleArray[a] } cnt++ } if (min == 1 && max == cnt) return cnt return -1 } function useJSON_GetObjectMembers(jsonSchema, prefix) { if (prefix == "") prefix = "<>" return prefix in jsonSchema ? jsonSchema[prefix] : "" } # quick sort array arr function utlJSON_qsortArray(arr, left, right, i, last, t) { if (left >= right) # do nothing if array has less than 2 elements return i = left + int((right-left+1)*rand()) t = arr[left]; arr[left] = arr[i]; arr[i] = t last = left # arr[left] is now partition element for (i = left+1; i <= right; i++) { if (arr[i] < arr[left]) { last++ t = arr[last]; arr[last] = arr[i]; arr[i] = t } } t = arr[left]; arr[left] = arr[last]; arr[last] = t utlJSON_qsortArray(arr, left, last-1) utlJSON_qsortArray(arr, last+1, right) } function useJSON_GetSchema(jsonData, jsonSchema, a, tidx, tv, sv, idx) { split("", jsonSchema) for (a in jsonData) { while (match(a, SUBSEP "[^" SUBSEP "]+$")) { tidx = substr(a,1,RSTART-1) tv = substr(a,RSTART+1) sv = (tidx in jsonSchema) ? jsonSchema[tidx] : "" # if ( sv != tv && sv !~ "^" tv SUBSEP && sv !~ SUBSEP tv "$" && sv !~ SUBSEP tv SUBSEP ) # Rephrase this using index so object member names with regex characters work if ( sv != tv && index(sv, tv SUBSEP) != 1 && (length(sv) <= length(tv)+1 || substr(sv, length(sv)-length(tv)) != SUBSEP tv) && index(sv, SUBSEP tv SUBSEP) == 0 ) jsonSchema[tidx] = sv (sv == "" ? "" : SUBSEP) tv a = tidx } tidx = "<>" tv = a sv = (tidx in jsonSchema) ? jsonSchema[tidx] : "" if ( sv != tv && sv !~ "^" tv SUBSEP && sv !~ SUBSEP tv "$" && sv !~ SUBSEP tv SUBSEP ) jsonSchema[tidx] = sv (sv == "" ? "" : SUBSEP) tv } } function useJSON_EscapeString(s, ii, c, t, t2, t3, t4, cs) { cs = "\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377" gsub(/\\/, "\\u005C", s) gsub(/"/, "\\\"", s) #gsub(/\//, "\\/", s) # required to decode, but not to encode gsub(/\b/, "\\b", s) gsub(/\f/, "\\f", s) gsub(/\n/, "\\n", s) gsub(/\r/, "\\r", s) gsub(/\t/, "\\t", s) for ( ii = 1 ; ii <= length(s) ; ii++ ) { t = substr(s,ii,1) if (t == "\000") # having \000 in list below doesnt work in all awks { c = 0 s = (ii > 1 ? substr(s, 1, ii-1) : "") sprintf("\\u%04X", c) (ii==length(s) ? "" : substr(s, ii+1)) ii += 5 } else { c = index("\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037", t) c = c == 0 ? -1 : c if ( c >= 0 ) { s = (ii > 1 ? substr(s, 1, ii-1) : "") sprintf("\\u%04X", c) (ii==length(s) ? "" : substr(s, ii+1)) ii += 5 } } t = index(cs, t) t2 = ii+1 <= length(s) ? index(cs, substr(s,ii+1,1)) : 0 t3 = ii+2 <= length(s) ? index(cs, substr(s,ii+2,1)) : 0 t4 = ii+3 <= length(s) ? index(cs, substr(s,ii+3,1)) : 0 if ( c < 0 && t > 64 && t <= 96 && ii+1 <= length(s) && t2 > 0 && t2 <= 64) # two character UTF-8 sequence { c = (t - 65)*64 + (t2-1) s = (ii > 1 ? substr(s, 1, ii-1) : "") sprintf("\\u%04X", c) (ii+1==length(s) ? "" : substr(s, ii+2)) ii += 5 } else if ( c < 0 && t > 96 && t <= 112 && ii+2 <= length(s) && t2 > 0 && t2 <= 64 && t3 > 0 && t3 <= 64) # three character UTF-8 sequence { c = (t - 97)*4096 + (t2-1)*64 + (t3-1) if ( c < 65536 ) { s = (ii > 1 ? substr(s, 1, ii-1) : "") sprintf("\\u%04X", c) (ii+2==length(s) ? "" : substr(s, ii+3)) ii += 5 } else { # encode in JSON-style with two \u#### UTF-16 surrogates # printf("1: %08X\n", c) s = (ii > 1 ? substr(s, 1, ii-1) : "") sprintf("\\u%04X\\u%04X", (c/1024)%1024 + 55296, c%1024 + 56320) (ii+3==length(s) ? "" : substr(s, ii+4)) ii += 11 } } # four character UTF-8 sequence, encode in JSON-style with two \u#### UTF-16 surrogates else if ( c < 0 && t > 112 && t <= 120 && ii+3 <= length(s) && t2 > 0 && t2 <= 64 && t3 > 0 && t3 <= 64 && t4 > 0 && t4 <= 64) { c = (t - 113)*262144 + (t2-1)*4096 + (t3-1)*64 + (t4-1) # printf("2: %08X, %d, %d, %d, %d\n", c, t, t2, t3, t4) # printf("\\u%04X\\u%04X\n", (c/1024)%1024 + 55296, c%1024 + 56320) c -= 65536 s = (ii > 1 ? substr(s, 1, ii-1) : "") sprintf("\\u%04X\\u%04X", (c/1024)%1024 + 55296, c%1024 + 56320) (ii+3==length(s) ? "" : substr(s, ii+4)) ii += 11 } } return "\"" s "\"" } function useJSON_GetDataValue(jsonData, prefix) { return prefix in jsonData ? jsonData[prefix] : "<>" } function useJSON_PrettyFormat(s, pretty) { if (s == "" || pretty <= 0) return s # dont sprintf the whole thing, some awks have short buffers for sprintf return sprintf("%*.*s", (pretty-1)*3, (pretty-1)*3, "") s (s == "}" || s == "]" ? "" : "\n") } function useJSON_FormatInt(jsonData, jsonSchema, prefix, pretty, allLines, member, memberArr, memberList, arrCount, a, ii) { memberList = useJSON_GetObjectMembers(jsonSchema, prefix) if ( memberList == "" ) { a = useJSON_GetDataValue(jsonData, prefix) if ( a == "<>" ) return "true" if ( a == "<>" ) return "false" if ( a == "<>" ) return "null" if ( a == "<>" ) return "" # <> is a help for dealing with empty arrays and objects # if it looks like a number, encode it as such. Cant tell a string from a number. if (a "" ~ /^(\-?)(0|[123456789][0123456789]*)(\.[0123456789]+)?([eE][+-]?[0123456789]+)?$/) return a return useJSON_EscapeString(a) } split(memberList, memberArr, SUBSEP) arrCount = useJSON_ArrayCount( memberArr ) if ( arrCount >= 0 ) { allLines = "[" (pretty == 0 ? "" : "\n") for ( ii = 1 ; ii <= arrCount ; ii++ ) allLines = allLines useJSON_PrettyFormat(useJSON_FormatInt( jsonData, jsonSchema, prefix (prefix == "" ? "" : SUBSEP) ii, (pretty != 0 ? pretty+1 : 0)) (ii < arrCount ? "," : ""), pretty != 0 ? pretty+1 : 0) allLines = allLines useJSON_PrettyFormat("]", pretty) return allLines } allLines = "{" (pretty == 0 ? "" : "\n") ii = 0 arrCount = 0 for (a in memberArr) arrCount++ utlJSON_qsortArray(memberArr, 1, arrCount) for ( ii = 1 ; ii <= arrCount ; ii++ ) allLines = allLines useJSON_PrettyFormat(useJSON_EscapeString(memberArr[ii]) (pretty == 0 ? ":" : " : ") useJSON_FormatInt(jsonData, jsonSchema, prefix (prefix == "" ? "" : SUBSEP) memberArr[ii], (pretty != 0 ? pretty+1 : 0)) (ii < arrCount ? "," : ""), pretty != 0 ? pretty+1 : 0) allLines = allLines useJSON_PrettyFormat("}", pretty) return allLines } # # Entry Points # # # ParseJSON : Parse JSON text into an awk array # # jsonString : JSON text # jsonData : array of parsed JSON data # # returns : N/A # function ParseJSON(jsonString, jsonData, jsonStringArr, cnt) { # newlines split differently in some awks, replace them with formfeeds (also white space) # if (split("1\n2\n3", jsonData, ",") == 3) # is this an awk that splits newlines differently? gsub(/\n/, "\f", jsonString) # always replace literal newlines - allows compatibility when testing split("", jsonData) # clear the array jsonData cnt = split(jsonString, jsonStringArr, ",") prsJSON_ParseJSONInt(jsonStringArr, cnt, 1, jsonData, "") } # # FormatJSON : Format parsed JSON data back into JSON text # # jsonData : array of parsed JSON data # pretty : 0 = compact format, non-zero = pretty format # # returns : string with JSON text # function FormatJSON(jsonData, pretty, jsonSchema) { useJSON_GetSchema(jsonData, jsonSchema) return useJSON_FormatInt(jsonData, jsonSchema, "", pretty ? 1 : 0) } # # JSONArrayLength : Find number of members in a JSON array # # jsonData : array of parsed JSON data # prefix : array name # # returns : number of entries in the array # function JSONArrayLength(jsonData, prefix, a, cnt, tv) { cnt = -1 for (a in jsonData) { if (prefix == "" || index(a, prefix) == 1) { tv = substr(a, prefix == "" ? 1 : (1+length(prefix)+1)) if ( index(tv, SUBSEP) ) tv = substr(tv, 1, index(tv, SUBSEP)-1) tv = tv + 0 if ( tv > cnt ) cnt = tv } } return cnt } # # JSONUnescapeString : turn a JSON-escaped string into UTF-8 # # jsonString : the escaped JSON string to convert # # returns : the string in UTF-8 # function JSONUnescapeString(jsonString) { return prsJSON_UnescapeString(jsonString) } # # JSONIsTrue : return non-zero if the value is the true value # # jsonValue : the value to test # # returns : true or false # function JSONIsTrue(jsonValue) { return jsonValue == "<>"; } # # JSONIsFalse : return non-zero if the value is the false value # # jsonValue : the value to test # # returns : true or false # function JSONIsFalse(jsonValue) { return jsonValue == "<>"; } # # JSONIsNull : return non-zero if the value is the null value # # jsonValue : the value to test # # returns : true or false # function JSONIsNull(jsonValue) { return jsonValue == "<>"; } # # JSONObjectMembers : get the set of members of an object # # jsonData : array of parsed JSON data # prefix : object name # memberArr : [out] an array of the names of the object members, if the target was an object or an array # # returns : If the target was actually an array rather than an object, the number of elements in the array # Else, zero if the target was an object or a value # function JSONObjectMembers(jsonData, prefix, memberArr, jsonSchema, memberList, rv, a) { useJSON_GetSchema(jsonData, jsonSchema) memberList = useJSON_GetObjectMembers(jsonSchema, prefix) if ( memberList == "" ) { split("", memberArr) return 0 } split(memberList, memberArr, SUBSEP) rv = useJSON_ArrayCount( memberArr ) if ( rv == -1 ) # not an array, sort the object member names { rv = 0 for (a in memberArr) rv++ utlJSON_qsortArray(memberArr, 1, rv) rv = 0 } return rv } # End of Copyright (c) 2010 Dan Saar function debug(lvl, text) { if (lvl <= DEBUG) print text > "/dev/stderr" } function wpt_init() { available = "True" archived = "False" sym = "Geocache" json_log_bool = 0 logs = "" logs_section = 0 hints = "" lat = "" yy = 0 wplist = "" nattr_yes = 0 nattr_no = 0 gs_type = "" } function dec2utf(dec) { if (dec <= 0x7f) return sprintf("%c", dec) else if (dec <= 0x07ff) return sprintf("%c%c", 0xC0 + rshift(dec, 6), 0x80 + and(dec, 0x3F) ) } function asc2xml(txt, o, ent, dec) { o = "" while (match(txt, "&#x[0123456789abcdefABCDEF]*;")) { o = o substr(txt, 1, RSTART-1) ent = toupper(substr(txt, RSTART+3, RLENGTH-4)) txt = substr(txt, RSTART+RLENGTH) dec = hex2dec(ent) o = o dec2utf(dec) } txt = o txt o = "" while (match(txt, "&#[0123456789]*;")) { o = o substr(txt, 1, RSTART-1) ent = toupper(substr(txt, RSTART+2, RLENGTH-3)) txt = substr(txt, RSTART+RLENGTH) dec = ent + 0 o = o dec2utf(dec) } o = o txt return o } function umlauts(text) { text = asc2xml(text) if(0) { # Somewhat minimal translation of HTML entities in titles gsub("ä", "\xc3\xa4", text) gsub("ä", "\xc3\xa4", text) gsub("ö", "\xc3\xb6", text) gsub("ö", "\xc3\xb6", text) gsub("ü", "\xc3\xbc", text) gsub("ü", "\xc3\xbc", text) gsub("Ä", "\xc3\x84", text) gsub("Ä", "\xc3\x84", text) gsub("Ö", "\xc3\x96", text) gsub("Ö", "\xc3\x96", text) gsub("Ü", "\xc3\x9c", text) gsub("Ü", "\xc3\x9c", text) gsub("ß", "\xc3\x9f", text) gsub("ß", "\xc3\x9f", text) gsub("°", "\xc2\xb0", text) gsub("°", "\xc2\xb0", text) gsub("´", "\xc2\xb4", text) gsub("´", "\xc2\xb4", text) } gsub("&", "\\&", text) return text } function htmlclean(text) { gsub(" ", " ", text) gsub("]*>", "\n", text) gsub("<[bB][rR][^>]*>", "\n", text) gsub("<[^>]*>", "", text) # compress whitespace gsub("\n\n\n*", "\n\n", text) gsub("[ \t][ \t]*", " ", text) return text } function tableclean(text) { gsub("\n", "", text) gsub(" ", " ", text) # translate/remove HTML tags gsub("]*>", "\n", text) gsub("]*>", "", text) gsub("]*>", "", text) gsub("]*>", "", text) gsub("", "", text) gsub("", "\n", text) gsub("]*>", " | ", text) gsub("<[^>]*>", "", text) # compress whitespace gsub("[ \t][ \t]*", " ", text) return text } function remdiv(text, tag) { if (tag != "") pat = ".*
]*>[ \t\n]*" else pat = ".*]*>[ \t\n]*" sub(pat, "", text) while (text !~ "/?div") { if (getline more <= 0) break text = text "\n" more } sub("[ \t\n]*
.*", "", text) debug(3, "Div:\n" text) return text } function remspan(text, tag) { if (tag != "") pat = ".*]*>[ \t\n]*" else pat = ".*]*>[ \t\n]*" sub(pat, "", text) while (text !~ "/?span") { if (getline more <= 0) break text = text "\n" more } sub("[ \t\n]*.*", "", text) debug(3, "Span:\n" text) return text } function remspanlong(text, tag) { if (tag != "") pat = ".*]*>[ \t\n]*" else pat = ".*]*>[ \t\n]*" sub(pat, "", text) # i = "span level" i = 1; j = 0 debug(2, length(text) "\t" i " " j++ " " text) # input is in text while (i != 0) { # emergency exit if (length(text) > 500000) { debug(0, "Warning: logs exceeded 500,000 bytes!") break } # cleanup: remove , adjust "span level" while (text ~ "") { if (text ~ "") { --i; sub("", "", text) } if (text ~ "") { ++i; sub("]*>", "", text) } } debug(2, "=" length(text) "\t" i " " j++ " " text) # if "span level" down to zero, closing tag reached if (i == 0) break # get more input if (getline more <= 0) break text = text "\n" more debug(2, "+" length(more) "\t" i " " j++ " " more) } debug(1, length(text) "\t" i " " j++) sub("[ \t\n]*.*", "", text) gsub(" ", " ", text) if (tag == "CacheLogs") gsub("]*>", "", text) debug(3, "SpanLong:\n" text) return text } function remwaypoints() { text = "" while (text !~ "" && text !~ "No additional waypoints to display") { if (getline more <= 0) break text = text " " more } gsub(" ", " ", text) gsub("\n[ \t]*", "", text) debug(3, "Waypoints:\n" text "\nEnd Waypoints") return text # will return complete table contents! split by instead of # } function splitwaypoints(waypoints, line, fld, prefix, lookup, wpname, x, y, lat, lon) { text="" # separate lines split(waypoints, wps, "") i = 0 for (wp in wps) ++i wp = 1 # skip header line while (wp < i) { ++wp # get URL from full table line url = wps[wp] gsub(".*href=.", "", url) gsub("\".*", "", url) if (url !~ "^http:") { url = "" } else { debug(1, "url: " url) } # individual fields without leading/trailing blanks, remove HTML tags split(wps[wp], line, "") j = 0 for (fld in line) { ++j debug(2, "Before Line[" fld "]: " line[fld]) gsub("[ \t]*<[^>]*>", "", line[fld]) gsub("^[ \t]*", "", line[fld]) gsub("[ \t]*$", "", line[fld]) debug(2, "after Line[" fld "]: " line[fld]) } # 8 fields: 1st line old style # 9 fields: 1st line new style # 4 fields, [1]~"Note:": 2nd line old style # 4 fields, [2]~"Note:": 2nd line new style # else: drop if (j == 8) { # main information line, old style (pre-2010/07) if (!line[3]) continue prefix = substr(line[3] "00", 1, 2) lookup = line[4] wpname = line[5] lat = toupper(line[6]) gsub(" *[EW].*", "", lat) split(lat, y) lat = y[2] + y[3]/60.0 if (y[1] == "S") lat = -lat lon = toupper(line[6]) gsub("[NS] *[0-9]*.. *[0-9.]* ", "", lon) gsub("[^ 0-9.NESW-]", "", lon) split(lon, x) lon = x[2] + x[3]/60.0 if (x[1] == "W") lon = -lon text = text sprintf("\nlat=\"%.6f\" lon=\"%.6f\"|%s|%s|%s|%s", lat, lon, prefix, lookup, wpname, url) } else if (j == 9) { # main information line, new style (2010/07) if (!line[4]) continue prefix = substr(line[4] "00", 1, 2) lookup = line[5] wpname = line[6] lat = toupper(line[7]) gsub(" *[EW].*", "", lat) split(lat, y) lat = y[2] + y[3]/60.0 if (y[1] == "S") lat = -lat lon = toupper(line[7]) gsub("[NS] *[0-9]*.. *[0-9.]* ", "", lon) gsub("[^ 0-9.NESW-]", "", lon) split(lon, x) lon = x[2] + x[3]/60.0 if (x[1] == "W") lon = -lon text = text sprintf("\nlat=\"%.6f\" lon=\"%.6f\"|%s|%s|%s|%s", lat, lon, prefix, lookup, wpname, url) } else if (j == 4) { if (line[1] ~ "Note:") { # continuation line, old style text = text sprintf("|%s", line[2]) } else if (line[2] ~ "Note:") { # continuation line, new style text = text sprintf("|%s", line[3]) } } } debug(3, "Split WPs\n" text) return text } function wpclean(waypoints, line, fld, prefix, lookup, wpname, coords) { # simplify Additional Waypoints table: # prefixedname - name
coordfield
note text = "" split(waypoints, wps, "") i = 0 for (wp in wps) ++i wp = 1 while (wp < i) { ++wp split(wps[wp], line, "") j = 0 for (fld in line) { ++j gsub("[ \t]*<[^>]*>", "", line[fld]) gsub("^[ \t]*", "", line[fld]) gsub("[ \t]*$", "", line[fld]) } # 8 fields: 1st line old style # 9 fields: 1st line new style # 4 fields, [1]~"Note:": 2nd line old style # 4 fields, [2]~"Note:": 2nd line new style # else: drop if (j == 8) { # main information line, old style (pre-2010/07) if (!line[3]) continue prefix = substr(line[3] "00", 1, 2) substr(gcid, 3) lookup = line[4] wpname = line[5] gsub(" \\(.*\\).*", "", wpname) coords = toupper(line[6]) text = text sprintf("%s - %s
%s
", prefix, wpname, coords) } else if (j == 9) { # main information line, new style (2010/07) if (!line[4]) continue prefix = substr(line[4] "00", 1, 2) substr(gcid, 3) lookup = line[5] wpname = line[6] gsub(" \\(.*\\).*", "", wpname) coords = toupper(line[7]) text = text sprintf("%s - %s
%s
", prefix, wpname, coords) } else if(j == 4) { if (line[1] ~ "Note:") { # continuation line, old style text = text sprintf("%s
", line[2]) } else if (line[2] ~ "Note:") { # continuation line, new style text = text sprintf("%s
", line[3]) } } } debug(3, "Clean WPs\n" text) return text } function hex2dec(x, val) { for (val = 0; length(x); x = substr(x, 2)) val = 16*val + index("0123456789ABCDEF", substr(x, 1, 1)) - 1 return val } # Convert GC0000 to 58913 function wp2id(wp, val) { sub("^GC", "", wp) debug(5, "wp2id: " wp " ...") if ((length(wp) <= 4) && (wp < "G000")) { # old hex style val = hex2dec(wp) debug(5, "wp2id hex: " val " ...") return val } # new style, base-31, can have 4 or more places! set = "0123456789ABCDEFGHJKMNPQRTVWXYZ" val = 0 for (pos = 1; pos <= length(wp); ++pos) { val *= 31 val += index(set, substr(wp, pos, 1)) - 1 } val = val - 411120 debug(5, "wp2id id: " val " ...") return val } # to decode hints: rot13 http://lorance.freeshell.org/rot13/ function rot13 (string) { ROTFROM = "nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM" ROTTO = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" retstr = "" for (pos = 0; pos < length(string); pos++) { char = substr(string,pos + 1,1) rotpos = index(ROTFROM,char) if (rotpos > 0) char = substr(ROTTO,rotpos,1) retstr = retstr char } return retstr } function tagstart(lvl, tag, parms) { printf "%*s", lvl*2, "" if (parms == "") printf "<%s>\n", tag else printf "<%s %s>\n", tag, parms } function tagend(lvl, tag) { printf "%*s", lvl*2, "" printf "\n", tag } function ee(text) { gsub(/&/, "\\&", text) gsub(//, "\\>", text) return text } function tagtext(lvl, tag, text) { text = ee(text) printf "%*s", lvl*2, "" printf "<%s>%s\n", tag, text, tag } function tagptext(lvl, tag, parms, text) { text = ee(text) printf "%*s", lvl*2, "" printf "<%s %s>%s\n", tag, parms, text, tag } function attr_begin1(gif, id, text) { debug(1, "attr_begin1: " gif " " id " \"" text "\"") attr_id[gif] = id; attr_text[gif] = text debug(1, "attr_id: " attr_id["slealth"]) debug(1, "attr_id: " attr_id[gif]) } function attr_begin() { # attr_begin1("slealth", 40, "Stealth required") Dont work!!! attr_id["dog"] = 1; attr_text["dog"] = "Dogs" attr_id["dogs"] = 1; attr_text["dogs"] = "Dogs" attr_id["fee"] = 2; attr_text["fee"] = "Access or parking fee" attr_id["rappelling"] = 3; attr_text["rappelling"] = "Climbing gear" attr_id["boat"] = 4; attr_text["boat"] = "Boat" attr_id["scuba"] = 5; attr_text["scuba"] = "Scuba gear" attr_id["kids"] = 6; attr_text["kids"] = "Recommended for kids" attr_id["onehour"] = 7; attr_text["onehour"] = "Takes less than an hour" attr_id["scenic"] = 8; attr_text["scenic"] = "Scenic view" attr_id["hiking"] = 9; attr_text["hiking"] = "Significant hike" attr_id["climbing"] = 10; attr_text["climbing"] = "Difficult climbing" attr_id["wading"] = 11; attr_text["wading"] = "May require wading" attr_id["swimming"] = 12; attr_text["swimming"] = "May require swimming" attr_id["available"] = 13; attr_text["available"] = "Available at all times" attr_id["night"] = 14; attr_text["night"] = "Recommended at night" attr_id["winter"] = 15; attr_text["winter"] = "Available during winter" attr_id["poisonoak"] = 16; attr_text["poisonoak"] = "Poison plants" attr_id["dangerousanimals"] = 17; attr_text["dangerousanimals"] = "Dangerous Animals" attr_id["ticks"] = 18; attr_text["ticks"] = "Ticks" attr_id["mines"] = 19; attr_text["mines"] = "Abandoned mines" attr_id["cliff"] = 20; attr_text["cliff"] = "Cliff / falling rocks" attr_id["hunting"] = 21; attr_text["hunting"] = "Hunting" attr_id["danger"] = 22; attr_text["danger"] = "Dangerous area" attr_id["wheelchair"] = 23; attr_text["wheelchair"] ="Wheelchair accessible" attr_id["parking"] = 24; attr_text["parking"] = "Parking available" attr_id["public"] = 25; attr_text["public"] = "Public transportation" attr_id["water"] = 26; attr_text["water"] = "Drinking water nearby" attr_id["restrooms"] = 27; attr_text["restrooms"] ="Public restrooms nearby" attr_id["phone"] = 28; attr_text["phone"] = "Telephone nearby" attr_id["picnic"] = 29; attr_text["picnic"] = "Picnic tables nearby" attr_id["camping"] = 30; attr_text["camping"] = "Camping available" attr_id["bicycles"] = 31; attr_text["bicycles"] = "Bicycles" attr_id["motorcycles"] = 32; attr_text["motorcycles"] = "Motorcycles" attr_id["quads"] = 33; attr_text["quads"] = "Quads" attr_id["jeeps"] = 34; attr_text["jeeps"] = "Off-road vehicles" attr_id["snowmobiles"] = 35; attr_text["snowmobiles"] = "Snowmobiles" attr_id["horses"] = 36; attr_text["horses"] = "Horses" attr_id["campfires"] = 37; attr_text["campfires"] = "Campfires" attr_id["thorns"] = 38; attr_text["thorns"] = "Thorns" attr_id["stealth"] = 39; attr_text["stealth"] = "Stealth required" attr_id["stroller"] = 40; attr_text["stroller"] = "Stroller accessible" attr_id["firstaid"] = 41; attr_text["firstaid"] = "Needs maintenance" attr_id["cow"] = 42; attr_text["cow"] = "Watch for livestock" attr_id["flashlight"] = 43; attr_text["flashlight"] = "Flashlight required" attr_id["landf"] = 44; attr_text["landf"] = "Lost And Found Tour" attr_id["rv"] = 45; attr_text["rv"] = "Recreational Vehicle" attr_id["field"] = 46; attr_text["field"] = "Field Puzzle" attr_id["UV"] = 47; attr_text["UV"] = "UV Light Required" attr_id["snowshoes"] = 48; attr_text["snowshoes"] = "Snowshoes" attr_id["skiis"] = 49; attr_text["skiis"] = "Cross Country Skis" attr_id["s-tool"] = 50; attr_text["s-tool"] = "Special Tool Required" attr_id["nightcache"] = 51; attr_text["nightcache"] = "Night Cache" attr_id["parkngrab"] = 52; attr_text["parkngrab"] = "Park and Grab" attr_id["AbandonedBuilding"] = 53; attr_text["AbandonedBuilding"] = "Abandoned Structure" attr_id["hike_short"] = 54; attr_text["hike_short"] = "Short hike (less than 1km)" attr_id["hike_med"] = 55; attr_text["hike_med"] = "Medium hike (1km-10km)" attr_id["hike_long"] = 56; attr_text["hike_long"] = "Long hike (+10km)" attr_id["fuel"] = 57; attr_text["fuel"] = "Fuel Nearby" attr_id["food"] = 58; attr_text["food"] = "Food Nearby" attr_id["wirelessbeacon"] = 59; attr_text["wirelessbeacon"] = "Wireless Beacon" attr_id["partnership"] = 60; attr_text["partnership"] = "Partnership" attr_id["seasonal"] = 61; attr_text["seasonal"] = "Seasonal Access" attr_id["tourist"] = 62; attr_text["tourist"] = "Tourist Friendly" attr_id["treeclimbing"] = 63; attr_text["treeclimbing"] = "Tree Climbing" attr_id["frontyard"] = 64; attr_text["frontyard"] = "Front Yard (Private Residence)" attr_id["teamwork"] = 65; attr_text["teamwork"] = "Teamwork Required" } function tagattr(lvl, kind, yesno) { kind = kind "" #debug(1, "kind: \"" kind "\"") if (attr_id[kind] == 0) return printf "%*s", lvl*2, "" printf "", attr_id[kind], yesno printf "%s", attr_text[kind] printf "\n" } /cache_types.aspx/ { # gc 02/01/11 gs_type = $0 sub(/.* alt=./, "", gs_type) sub(/. width=.*/, "", gs_type) sub(/. title=.*/, "", gs_type) debug(1, "gs_type: " gs_type) } // { if (gs_type) { gs_name = remspan($0, "ctl00_ContentBody_CacheName") next } gs_type = $0 sub(/.* alt=./, "", gs_type) sub(/. width=.*/, "", gs_type) debug(1, "type: " gs_type) } // { gs_name = remspan($0, "CacheName") } // { gs_name = remspan($0, "ctl00_ContentBody_CacheName") } // { gcid = remspan($0) } /;wp=GC.*" / { # new way, yech! gcid = $0; sub(/.*wp=/, "", gcid); sub(/".*/, "", gcid) } // { gs_short_description = remspan($0) } // { gs_long_description = remspanlong($0, "LongDescription") waypoints = "" } // { gs_long_description = remspanlong($0, "ctl00_ContentBody_LongDescription") waypoints = "" } /
", "\n", hints) if (DECODE) hints=rot13(hints) } /", "", hints) sub(".*", "", hints) gsub("
", "\n", hints) # debug(1, "Hints: " hints) if (DECODE) hints=rot13(hints) } /Additional Waypoints/ { waypoints = remwaypoints() wplist = splitwaypoints(waypoints) } /Additional Waypoints/ { waypoints = remwaypoints() wplist = splitwaypoints(waypoints) } # 03/01/2011 /ContentBody_WaypointsInfo/ { waypoints = remwaypoints() wplist = splitwaypoints(waypoints) } /class="LogsTable Table"/ { # old logs_section = 1 } /class="LogsTable"/ { # new 06/28/11 logs_section = 1 } (logs_section > 0) { logs = logs $0 } (logs_section > 0) && / 0) && /<\/table>/ { logs_section -= 1 } // { logs = remspanlong($0, "CacheLogs") # remove header which does not exist >2010-01-12 sub(".*td class=.containerHeader.>Cache Logs", "", logs) } // { logs = remspanlong($0, "ctl00_ContentBody_CacheLogs") } // { stats = remspan($0) } // { numvisits = remspan($0) debug(1, numvisits) } /lnkPrintFriendly/ { gid = $0 if (gid ~ /ID=/) { # Printable page has ID number sub(/^.*ID=/, "", gid) sub(/&.*/, "", gid) } else { # Non-printable page has guid number sub(/^.*guid=/, "", gid) sub(/&.*/, "", gid) } } # Add optional "A cache ". 08/21/2012 /^ *(A cache )*by /, "", gs_owner) sub(/<.*/, "", gs_owner) debug(1, "owner: " gs_owner) gs_guid = $0 sub(/.*guid=/, "", gs_guid) sub(/&.*/, "", gs_guid) } # Fake gs_guid is user 03/01/2011 /userInfo = {ID:/ { gs_guid = $0 sub(/.*: /, "", gs_guid) sub(/}.*/, "", gs_guid) debug(1, "guid " gs_guid) } /.* alt=.Size/ { gs_size = $0 sub(/.*Size: /, "", gs_size); sub(". />.*", "", gs_size) } /by /, "", gs_owner); sub(/ [[].*/, "", gs_owner) debug(1, gs_owner) sub(/]*>/, "", gs_owner) sub(/<.a[^>]*>/, "", gs_owner) sub(/.*
/, "", gs_owner) sub(/^by /, "", gs_owner) debug(1, "owner " gs_owner) gs_size = text; sub(/.*Size: /, "", gs_size); sub(/<.*/, "", gs_size) gs_guid = text; sub(/.*guid=/, "", gs_guid) sub(/&.*/, "", gs_guid) debug(1, "guid " gs_guid) } //, "", gs_type) debug(1, "gs_type: " gs_type) gs_owner = text sub(/.*ds=2.>/, "", gs_owner); sub(/<.*/, "", gs_owner) debug(1, "gs_owner: " gs_owner) gs_size = text; sub(/.*Size: /, "", gs_size); sub(/<.*/, "", gs_size) gs_guid = text; sub(/.*guid=/, "", gs_guid) sub(/&.*/, "", gs_guid) sub(/. title=.*/, "", gs_guid) debug(1, "guid: " gs_guid) } /Hidden/ { # gc 2/1/11 getline time getline time sub(/^ */, "", time) sub(/<.*/, "", time) split(time, fld, "/") time = sprintf("%d-%02d-%02d", fld[3], fld[1], fld[2]) debug(1, "time: " time) } /> / { # gc 6/28/11 getline time getline time getline time sub(/^ */, "", time) sub(/<.*/, "", time) gsub(/-/, "/", time) rc = split(time, fld, "/") if (rc == 1) rc = split(time, fld, "-") debug(1, "timerc: " rc) if (DATEFMT == 1) time = sprintf("%d-%02d-%02d", fld[3], fld[2], fld[1]) else if (fld[1] >= 1000) time = sprintf("%d-%02d-%02d", fld[1], fld[2], fld[3]) else time = sprintf("%d-%02d-%02d", fld[3], fld[1], fld[2]) debug(1, "time: " time) } // { getline text time = remspan($0) split(time, fld, "/") time = sprintf("%d-%02d-%02d", fld[3], fld[1], fld[2]) } // { time = remspan($0, "ctl00_ContentBody_DateHidden") rc = split(time, fld, "/") if (rc == 3) { time = sprintf("%d-%02d-%02d", fld[3], fld[1], fld[2]) debug(1, "time: " time) next } rc = split(time, fld, ",") if (rc == 3) { yyyy = fld[3]; split(fld[2], fld, " ") mm = Month[ fld[1] ] dd = fld[2] time = sprintf("%d-%02d-%02d", yyyy, mm, dd) debug(1, "time: " time) next } time = "" } /ctl00_ContentBody_uxLegendScale/ { text = $0 sub(/.*alt=./, "", text); sub(/ .*/, "", text) gs_diff = text debug(1 , "gs_diff: " gs_diff) } /ctl00_ContentBody_Localize/ { text = $0 sub(/.*alt=./, "", text); sub(/ .*/, "", text) gs_terr = text debug(1 , "gs_terr: " gs_terr) } /^ *Difficulty:<.strong>/ { getline text sub(/.*alt=./, "", text); sub(/ .*/, "", text) gs_diff = text debug(1 , "gs_diff: " gs_diff) } /^ *Difficulty:/ { # gc 2/1/11 getline text getline text getline text sub(/.*alt=./, "", text); sub(/ .*/, "", text) gs_diff = text debug(1 , "gs_diff: " gs_diff) } // { text = remspan($0) sub(/.*alt=./, "", text); sub(/ .*/, "", text) gs_diff = text } // { text = remspan($0, "ctl00_ContentBody_Difficulty") sub(/.*alt=./, "", text); sub(/ .*/, "", text) debug(1, "difficulty " text) gs_diff = text } /^ *Terrain:<.strong>/ { getline text sub(/.*alt=./, "", text); sub(/ .*/, "", text) gs_terr = text debug(1 , "gs_terr: " gs_terr) } /^ *Terrain:/ { # gc 2/1/11 getline text getline text getline text sub(/.*alt=./, "", text); sub(/ .*/, "", text) gs_terr = text debug(1 , "gs_terr: " gs_terr) } // { text = remspan($0) sub(/.*alt=./, "", text); sub(/ .*/, "", text) gs_terr = text } // { text = remspan($0, "ctl00_ContentBody_Terrain") sub(/.*alt=./, "", text); sub(/ .*/, "", text) debug(1, "terrain " text) gs_terr = text } /title=.What are Attributes?/ { text = $0 debug(5, "Attr " text) gsub("[^/, "", text) # after 06/03/10 gsub(/alt="[^"]*" title="[^"]*" width="30" height="30" .>/, "", text) gsub("

/ { if ((lat == "") || (lon == "")) { debug(0, "Waypoint coordinates not found for " gcid ", no output!") #next } # too long a block to be indented if (!INCR && first) { print "" tagstart(0, "gpx") tagtext(1, "desc", "Geocache file generated by geo-html2gpx") tagtext(1, "author", "geo-html2gpx") "date +%Y-%m-%dT%H:%M:%S" | getline date tagtext(1, "time", date) first = 0 } gs_name = umlauts(gs_name) gs_owner = umlauts(gs_owner) tagstart(1, "wpt", "lat=\"" lat "\" lon=\"" lon "\"") if (time != "") tagtext(2, "time", time "T07:00:00Z") tagtext(2, "name", gcid) tagtext(2, "desc", gs_name " by " gs_owner ", " \ gs_type " (" gs_diff "/" gs_terr ")") # alternate URL... tagtext(2, "url", BaseURL "?wp=" gcid) # alternate URL... tagtext(2, "url", BaseURL "?id=" gid) tagtext(2, "url", BaseURL "?wp=" gcid) tagtext(2, "urlname", gs_name) # we do this last... tagtext(2, "sym", sym) tagtext(2, "type", "Geocache|" gs_type) # FIXME? GC-written GPX files contain numeric, non-UUID, # cache/owner/finder ids # Oregon needs numeric cache id, or behaves erratically! gid = wp2id(gcid) tagstart(2, "groundspeak:cache", "id=\"" gid "\" available=\"" available \ "\" archived=\"" archived "\"" \ " xmlns:groundspeak=\"http://www.groundspeak.com/cache/1/0/1\"") tagtext(3, "groundspeak:name", gs_name) tagtext(3, "groundspeak:placed_by", gs_owner) tagptext(3,"groundspeak:owner", "id=\"" gs_guid "\"", gs_owner) tagtext(3, "groundspeak:type", gs_type) tagtext(3, "groundspeak:container", gs_size) if (nattr_yes != 0 || nattr_no != 0) { tagstart(3, "groundspeak:attributes") for (i = 1; i <= nattr_yes; ++i) tagattr(4, attr_yes[i], 1) for (i = 1; i <= nattr_no; ++i) tagattr(4, attr_no[i], 0) tagend(3, "groundspeak:attributes") } tagtext(3, "groundspeak:difficulty", gs_diff) tagtext(3, "groundspeak:terrain", gs_terr) tagtext(3, "groundspeak:country", gs_country) tagtext(3, "groundspeak:state", gs_state) if (!NOHTML) { tagptext(3, "groundspeak:short_description", "html=\"True\"", gs_short_description) if (!NOWPTS && waypoints) { # reproduce "simplified table" by GC PQ # prefixed_gcid - wpname
original_style_coord
note
waypoints = wpclean(waypoints) # include "zero" waypoints here! gs_long_description = gs_long_description \ "

Additional Waypoints

" waypoints } tagptext(3, "groundspeak:long_description", "html=\"True\"", gs_long_description) } else { gs_short_description = htmlclean(gs_short_description) tagptext(3, "groundspeak:short_description", "html=\"False\"", gs_short_description) gs_long_description = htmlclean(gs_long_description) if (waypoints) gs_long_description = gs_long_description \ "\n\nAdditional Waypoints\n" tableclean(waypoints) tagptext(3, "groundspeak:long_description", "html=\"False\"", gs_long_description) } tagtext(3, "groundspeak:encoded_hints", hints) if (json_log_bool) { nlogs = JSONArrayLength(json_logs, "data") if (nlogs > NUMLOGS+1) nlogs = NUMLOGS+1 debug(1, "New Logs: " nlogs) if (nlogs > 1) tagstart(3, "groundspeak:logs") else tagstart(3, "groundspeak:logs", "/") for (i = 1; i < nlogs; ++i) { ltype = json_logs["data" SUBSEP i SUBSEP "LogTypeImage"] if (ltype ~ /smile/) ltype = "Found it" else if (ltype ~ /happy/) ltype = "Found it" else if (ltype ~ /note/) ltype = "Write note" else if (ltype ~ /sad/) ltype = "Didn'"'"'t Find it" else if (ltype ~ /attended/) ltype = "Attended" else if (ltype ~ /rsvp/) ltype = "Will Attend" else if (ltype ~ /greenlight/) ltype = "Green" else if (ltype ~ /traffic_cone/) ltype = "Archive" else if (ltype ~ /disabled/) ltype = "Temporarily Disable Listing" else if (ltype ~ /coord_update/) ltype = "Update Coordinates" else ltype = "Unknown" ldate = json_logs["data" SUBSEP i SUBSEP "Visited"] n = split(ldate, fld, "/") if (n == 3) { #new format: 08/18/2011 if (DATEFMT == 1) ldate = sprintf("%d-%02d-%02dT20:00:00Z", fld[3], fld[2], fld[1]) else ldate = sprintf("%d-%02d-%02dT20:00:00Z", fld[3], fld[1], fld[2]) debug(2, "logdate: " ldate) } lfinder = json_logs["data" SUBSEP i SUBSEP "UserName"] lfinder = umlauts(lfinder) logid = json_logs["data" SUBSEP i SUBSEP "LogID"] guid = json_logs["data" SUBSEP i SUBSEP "AccountID"] ltext = json_logs["data" SUBSEP i SUBSEP "LogText"] ltext = htmlclean(ltext) ltext = umlauts(ltext) if (lfinder == USERNAME && ltype == "Found it") sym = "Geocache Found" if (lfinder == USERNAME && ltype == "Attended") sym = "Geocache Found" tagstart(4, "groundspeak:log", "id=\"" logid "\"") tagtext(5, "groundspeak:date", ldate) tagtext(5, "groundspeak:type", ltype) tagptext(5, "groundspeak:finder", "id=\"" guid "\"", lfinder) tagptext(5, "groundspeak:text", "encoded=\"" "False" "\"", ltext) tagend(4, "groundspeak:log") } if (nlogs > 1) tagend(3, "groundspeak:logs") } else { # nlogs = split(logs, entry, "") nlogs = split(logs, entry, "
") if (nlogs > NUMLOGS+1) nlogs = NUMLOGS+1 if (nlogs > 1) tagstart(3, "groundspeak:logs") else tagstart(3, "groundspeak:logs", "/") for (i = 1; i < nlogs; ++i) { sub("]*>", "", entry[i]) sub("", "", entry[i]) if (!entry[i]) continue # old split location sub(/.*<[Ss][Tt][Rr][Oo][Nn][Gg]>.*/, "", ltype) # leaves the URL of the smiley if (ltype ~ /smile/) ltype = "Found it" else if (ltype ~ /happy/) ltype = "Found it" else if (ltype ~ /note/) ltype = "Write note" else if (ltype ~ /sad/) ltype = "Didn'"'"'t Find it" else if (ltype ~ /attended/) ltype = "Attended" else if (ltype ~ /rsvp/) ltype = "Will Attend" else if (ltype ~ /greenlight/) ltype = "Green" else if (ltype ~ /traffic_cone/) ltype = "Archive" else if (ltype ~ /disabled/) ltype = "Temporarily Disable Listing" else if (ltype ~ /coord_update/) ltype = "Update Coordinates" else ltype = "Unknown" ldate = entry[i] # split off  /blank sub(/^[^>]*>[^ ;]*[ ;]/, "", ldate) sub(/ by <.*/, "", ldate) sub(/ by /, "", ldate) sub(/.*LogDate.>about /, "", ldate) sub(/.*LogDate.>/, "", ldate) sub(/<.*/, "", ldate) gsub(/-/, "/", ldate) debug(1, "logdate: " ldate) if (ldate ~ /ago/) { cmd = sprintf("%s -d \"12am %s\" +%%Y-%%m-%%dT07:00:00Z", DATE, ldate) cmd | getline ldate; close(cmd) } else { n = split(ldate, fld, " ") if (n >= 2) { #old format: August 18 mm = Month[fld[1]] dd = fld[2] + 0 if (n >= 3) yy = fld[3] if (yy+0 == 0) yy = YR ldate = sprintf("%d-%02d-%02dT07:00:00", yy, mm, dd) } n = split(ldate, fld, "/") if (n == 3) { #new format: 08/18/2011 if (DATEFMT == 1) ldate = sprintf("%d-%02d-%02dT07:00:00", fld[3], fld[2], fld[1]) else ldate = sprintf("%d-%02d-%02dT07:00:00", fld[3], fld[1], fld[2]) debug(1, "logdate: " ldate) } } lfinder = entry[i] sub(/[^<]*]*>/, "", guid) # Delete all before .*/, "", guid) # Delete all after ]*>/, "", lfinder) # Delete all before ]*>/, "", lfinder) # Delete all before name sub(/<.*/, "", lfinder) # Delete all after name lfinder = umlauts(lfinder) debug(1, "lfinder: " lfinder) ltext = entry[i] sub(/.*found\)
/, "", ltext) sub(".*", "", ltext) sub("
]*>[^<]*", "", ltext) sub("]*>[^<]*", "", ltext) # remove remaining HTML tags from log text. Seems to be a good # idea in any case, independent of NOHTML setting! ltext = htmlclean(ltext) ltext = umlauts(ltext) if (lfinder == USERNAME && ltype == "Found it") sym = "Geocache Found" if (lfinder == USERNAME && ltype == "Attended") sym = "Geocache Found" tagstart(4, "groundspeak:log", "id=\"" logid "\"") tagtext(5, "groundspeak:date", ldate) tagtext(5, "groundspeak:type", ltype) tagptext(5, "groundspeak:finder", "id=\"" guid "\"", lfinder) tagptext(5, "groundspeak:text", "encoded=\"" "False" "\"", ltext) tagend(4, "groundspeak:log") } if (nlogs > 1) tagend(3, "groundspeak:logs") } tagstart(3, "groundspeak:travelbugs", "/") tagend(2, "groundspeak:cache") tagtext(2, "sym", sym) tagend(1, "wpt") # add Additional Waypoints in wpt form if (!NOWPTS && wplist) { split(wplist, wps, "\n") i = 0 for (wp in wps) ++i wp = 0 while (wp < i) { ++wp # lat lon|prefix|lookup|wpname|url|note # i.e.: lat="44.888267" lon="-93.159233"|PC|PARK|http://... # |GCPMG6-Parking (Parking Area)|.31 miles from cache. debug(1, "wps: " wps[wp]) split(wps[wp], line, "|") if (line[1] && (!NOZERO || (line[1] !~ "lat=\"0.000000\" lon=\"0.000000\"") ) ) { # line format: coords|prefix|lookup|wpname|note tagstart(1, "wpt", line[1]) #tagtext(2, "time", "...") tagtext(2, "name", line[2] substr(gcid,3)) tagtext(2, "cmt", line[6] ? line[6] : "") statname = line[4] gsub(" \\(.*\\).*", "", statname) desc = line[4] sub(" \\(.*", "", desc) tagtext(2, "desc", desc) tagtext(2, "url", line[5]) urlname = desc tagtext(2, "urlname", urlname) stattype = line[4] gsub(".*\\(", "", stattype) gsub("\\).*", "", stattype) tagtext(2, "sym", stattype) tagtext(2, "type", "Waypoint|" stattype) tagend(1, "wpt") } } } wpt_init() } END { if (!INCR && !first) tagend(0, "gpx") } ' | $POSTPROC