Simple parser for vCard, a file format standard for electronic business cards [http://en.wikipedia.org/wiki/VCard]. package provide vCard 2.1 # CR = ;(15, 13.) # LF = ;(12, 10.) # CRLF = CR LF # SPACE = ;(40, 32.) # HTAB = ;(11, 9.) # All literal property names are valid as upper, lower, or mixed case. # ws = 1*(SPACE | HTAB) ; "whitespace," one or more spaces or tabs # wsls = 1*(SPACE | HTAB | CRLF) ; whitespace with line separators # word = # groups = groups "." word | word # these may be "folded": # value = 7bit | quoted-printable | base64 # 7bit = <7bit us-ascii printable chars, excluding CR LF> # 8bit = # quoted-printable = # base64 = ; the end of the text is marked with two CRLF sequences this results in one blank line before the start of the next property # these may be "folded": # name = "LOGO" | "PHOTO" | "LABEL" | "FN" | "TITLE" | "SOUND" | "VERSION" | "TEL" | "EMAIL" | "TZ" | "GEO" | "NOTE" | "URL" | "BDAY" | "ROLE" | "REV" | "UID" | "KEY" | "MAILER" | "X-" word # knowntype = "DOM" | "INTL" | "POSTAL" | "PARCEL" | "HOME" | "WORK" | "PREF" | "VOICE" | "FAX" | "MSG" | "CELL" | "PAGER" | "BBS" | "MODEM" | "CAR" | "ISDN" | "VIDEO" | "AOL" | "APPLELINK" | "ATTMAIL" | "CIS" | "EWORLD" | "INTERNET" | "IBMMAIL" | "MCIMAIL" | "POWERSHARE" | "PRODIGY" | "TLX" | "X400" | "GIF" | "CGM" | "WMF" | "BMP" | "MET" | "PMB" | "DIB" | "PICT" | "TIFF" | "PDF" | "PS" | "JPEG" | "QTIME" | "MPEG" | "MPEG2" | "AVI" | "WAVE" | "AIFF" | "PCM" | "X509" | "PGP" # ptypeval = knowntype | "X-" word # pvalueval = "INLINE" | "URL" | "CONTENT-ID" | "CID" | "X-" word # pencodingval = "7BIT" | "8BIT" | "QUOTED-PRINTABLE" | "BASE64" | "X-" word # charsetval = # langval = # param = "TYPE" [ws] "=" [ws] ptypeval | "VALUE" [ws] "=" [ws] pvalueval | "ENCODING" [ws] "=" [ws] pencodingval | "CHARSET" [ws] "=" [ws] charsetval | "LANGUAGE" [ws] "=" [ws] langval | "X-" word [ws] "=" [ws] word | knowntype # paramlist = paramlist [ws] ";" [ws] param | param # params = ";" [ws] paramlist # nonsemi = # strnosemi = *(*nonsemi ("\;" | "\" CRLF)) *nonsemi ; To include a semicolon in this string, it must be escaped with a "\" character. # addressparts = 0*6(strnosemi ";") strnosemi ; PO Box, Extended Addr, Street, Locality, Region, Postal Code, Country Name # orgparts = *(strnosemi ";") strnosemi ; First is Organization Name, remainder are Organization Units. # nameparts = 0*4(strnosemi ";") strnosemi ; Family, Given, Middle, Prefix, Suffix. #; these may be "folded" # item = [groups "."] name [params] ":" value CRLF | [groups "."] "ADR" [params] ":" addressparts CRLF | [groups "."] "ORG" [params] ":" orgparts CRLF | [groups "."] "N" [params] ":" nameparts CRLF | [groups "."] "AGENT" [params] ":" vcard CRLF # items = items *CRLF item | item # vcard = "BEGIN" [ws] ":" [ws] "VCARD" [ws] 1*CRLF items *CRLF "END" [ws] ":" [ws] "VCARD" # vcard_file = [wsls] vcard [wsls] namespace eval vCard { variable encodings {BASE64 QUOTED-PRINTABLE 8BIT} variable params {ENCODING CHARSET LANGUAGE VALUE TYPE} variable values {INLINE URL CONTENT-ID} variable properties {FN} # FN - Formatted Name - specifies the formatted name string for vCard object. # N - Name - This property specifies a structured representation of the name of the person, place or thing - consists of the components of the name specified as positional fields separated by the Field Delimiter character (ASCII decimal 59). The property value is a concatenation of the Family Name (first field), Given Name (second field), Additional Names (third field), Name Prefix (fourth field), and Name Suffix (fifth field) strings. # PHOTO - Photograph - This property specifies an image or photograph of an individual variable ptype {GIF CGM WMF BMP MET PMB DIB PICT TIFF PS PDF JPEG MPEG MPEG2 AVI QTIME} # BDAY - Birthdate - date of birth of the individual associated with the vCard. The value for this property is a calendar date in a complete representation consistent with ISO 8601. # ADR - Delivery Address - components that are based on the X.500 Post Office Box attribute, the X.520 Street Address geographical attribute, the X.520 Locality Name geographical attribute, the X.520 State or Province Name geographical attribute, the X.520 Postal Code attribute, and the X.520 Country Name geographical attribute. variable adrParam {TYPE {DOM INTL POSTAL PARCEL HOME WORK}} # LABEL - Delivery Label - This property is based on the semantics of the X.520 Postal Address attribute. This specification has added semantics to those defined by the X.500 Series standard for differentiating Home, Work, Parcel, Postal, Domestic, and International delivery label types. OPT # TEL - Telephone Number - variable teltype {PREF WORK HOME VOICE FAX MSG CELL PAGER BBS MODEM CAR ISDN VIDEO} # EMAIL - variable emailType {INTERNET} # - Time Zone - ISO 8601 # AGENT - Agent - This property is equivalent to nesting another vCard with the specified vCard. # ORG - Organization Name and Organizational Unit - a concatenation of the Organization Name (first field), Organizational Unit (second field) strings. Additional positional fields, if specified, contain additional Organizational Units. # NOTE - Comment - # REV - Last Revision - calendar date and time of day of the last update to the vCard object ISO 8601 # SOUND - sound - variable soundType {WAVE PCM AIFF} # URL - - # UID - Unique Idxentifier - persistent, globally unique identifier associated with the object # VERSION - - vcard spec supported 2.1 # KEY - Public Key - variable keyType {X509 PGP} proc parse {text} { set state none regsub -all {\n[ \t]+} $text { } text set result {} foreach line [split $text \n] { set line [string trim $line] if {$line eq ""} continue set value [join [lassign [split $line :] begin] :] set groups [lassign [split $begin .] name] set params [lassign [split $name {;}] name] #puts stderr "parse: $name - $value" switch -glob -- [string toupper $name] { BEGIN { continue } END { return $result } ADR { lassign [split $value {;}] box ext street locality region postcode country foreach v {box ext street locality region postcode country} { dict set result address $v [set $v] } } ORG { set units [lassign [split $value {;}] orgname] dict set result org name $orgname dict set result org units $units } N { lassign [split $value {;}] family given middle prefix suffix foreach v {family given middle prefix suffix} { dict set result name $v [set $v] } } AGENT { error "Can't handle agents" } LOGO - PHOTO - LABEL - FN - TITLE - SOUND - VERSION - TEL - EMAIL - TZ - GEO - NOTE - URL - BDAY - ROLE - REV - UID - KEY - MAILER - X-* { dict set result $name $value } default { } } } return $result } namespace export -clear * namespace ensemble create -subcommands {} } ---- !!!!!! %| [Category Package] | [Category Office Automation] |% !!!!!!