#!/bin/zsh
-# Copyright 2014 - 2018 Paul Hänsch
+# Copyright 2014 - 2018, 2023 Paul Hänsch
#
# This file is part of Confetti.
#
BR='
'
+unescape(){
+ local in out=''
+ [ $# -gt 0 ] && in="$*" || in="$(cat)"
+ while [ "$in" ]; do case $in in
+ \\\\*) out="${out}\\"; in="${in#\\\\}" ;;
+ \\n*) out="${out}${BR}"; in="${in#\\n}" ;;
+ \\*) in="${in#\\}" ;;
+ *) out="${out}${in%%[\\]*}"; in="${in#"${in%%[\\]*}"}" ;;
+ esac; done
+ printf '%s\n' "$out"
+ }
pdi_load() {
- sed -En '
+ # normalise PDI file for processing with pdi_* functions
+ # functions in this library can only be applied to normalised data
+ # Usage example:
+ # data="$(pdi_load file.vcf)"
+
+ sed -srn '
# === Read entire file into buffer ===
:X $bY; N; bX; :Y s;^.*$;\n&\n;;
# === Join continuing lines, strip trailing CRs ===
- s;\r\n[ \t];;g;
- s;\r\n;\n;g;
+ s;\r*\n[ \t];;g;
+ s;\r*\n;\n;g;
# === turn property names to upper case, strip group names ===
s;\n([^;:\.\n]+\.)([^;:\n]+);\n\2;g;
# === Unscramble aggregated fields ===
:disag
- s;\n([^:]+:)((.*[^\])?(\\\\)*),;\n\1\2\n\1;;
+ s;\n([^:\n]+:)(([^\n]*[^\])?(\\\\)*),;\n\1\2\n\1;;
t disag;
# === Insert FN when only N is present ===
# === Update obsolete LABEL property ===
s;\nLABEL((\;[A-Za-z0-9-]+|\;[A-Za-z0-9-]+=([^;,:"]+|"[^"]+")(,[^;,:"]+|,"[^"]+")*)*):(.*)\n;\nADR\1\;LABEL="\5":\n;g;
- p;' "$1"
+ p;' "$@"
}
pdi_count(){
}
pdi_attrib(){
- local card=":$1" name="$2" cnt="${3:-1}"
+ local card=":$1" name="$2" cnt="${3:-1}" attr="$4"
while [ $cnt -gt 0 ]; do
[ "${card#*${BR}${name};}" = "$card" ] && return 1
card="${card#*${BR}${name};}"
cnt=$((cnt - 1))
done
- printf %s\\n "${card%%:*}"
+ card="${card%%:*}"
+ if [ "$attr" ]; then
+ case $card in
+ *\;"$attr"=*) card="${card#*;${attr}=}";;
+ "$attr"=*) card="${card#${attr}=}";;
+ "$attr"|*\;"$attr"|"$attr"\;*|*\;"$attr"\;*) return 0;;
+ *) return 1;;
+ esac
+ case $card in
+ \"*\"\;*|\'*\'\;*)
+ card="${card#[\"\']}"; card="${card%%[\"\'];*}"
+ ;;
+ \"*\"|\'*\')
+ card="${card#[\"\']}"; card="${card%%[\"\']}"
+ ;;
+ *\;*) card="${card%%;*}";;
+ esac
+ fi
+ printf %s\\n "${card}"
}
pdi_value(){
local card="${BR}$1" name="$2" cnt="${3:-1}"
- while [ $cnt -gt 0 ]; do
+ while [ "$cnt" -gt 0 ]; do
[ "${card#*${BR}${name};*:}" = "$card" ] && return 1
card="${card#*${BR}${name};*:}"
cnt=$((cnt - 1))
done
printf %s\\n "${card%%${BR}*}"
}
+
+pdi_update_value(){
+ local card="${BR}$1" name="$2" cnt="$3" val="$4"
+ while [ "$cnt" -gt 0 ]; do
+ if [ "${card#*${BR}${name};*:}" = "${card}" ]; then
+ printf '%s\n%s;:' "${card%${BR}END;:VCARD*}" "${name}"
+ card="${BR}END;:VCARD"
+ break;
+ else
+ printf '%s\n%s;' "${card%%${BR}${name};*}" "${name}"
+ card="${card#*${BR}${name};}"
+ printf '%s:' "${card%%:*}"
+ card="${card#*:}"
+ fi
+ cnt=$((cnt - 1))
+ done
+ printf '%s\n%s\n' "$val" "${card#*${BR}}"
+}
+
+pdi_update_attrib(){
+ local card="${BR}$1" name="$2" cnt="$3" val="$4"
+ while [ "$cnt" -gt 0 ]; do
+ if [ "${card#*${BR}${name};*:}" = "${card}" ]; then
+ printf '%s\n%s;' "${card%${BR}END;:VCARD*}" "${name}"
+ card=":${BR}END;:VCARD"
+ break;
+ else
+ printf '%s\n%s;' "${card%%${BR}${name};*}" "${name}"
+ card="${card#*${BR}${name};}"
+ fi
+ cnt=$((cnt - 1))
+ done
+ printf '%s:%s\n' "$val" "${card#*:}"
+}