Signal exception if input isn’t vCard

… with a somewhat naïve check. Also, also count
horizontal-tab characters as starters of folded
lines (as per spec).
This commit is contained in:
Jaidyn Ann 2024-02-12 22:10:43 -06:00
parent 5de1c57b18
commit 1bf429571f

View File

@ -21,6 +21,7 @@
(chicken base)
(chicken condition)
(chicken io)
(chicken irregex)
(srfi 1)
(srfi 4)
(srfi 13)
@ -223,24 +224,53 @@
(parse-vcard-value property value-elements))))
;; Reader thunk. Read/parse an entire vcard into a “vcard alist.”
(define (read-vcard)
(let [(element (read-vcard-element))]
;; Reader thunk. Read/parse an entire vCard into a “vCard alist.”
;; Ignore the IGNORED parameter.
(define (read-vcard . ignored)
(let* [(first-element? (optional ignored #t))
(element (read-vcard-element first-element?))]
(if (not (eof-object? (peek-char)))
(append (list element) (read-vcard))
(append (list element) (read-vcard #f))
(list element))))
;; Read a single unfolded line into a vcard “element” list.
(define (read-vcard-element)
(parse-vcard-line (read-folded-line)))
;; Read a single unfolded line into a vCard “element” list.
;; The optional FIRST-ELEMENT? argument simply makes sure the next line is a
;; BEGIN:VCARD element (as the first element in any valid vCard file should
;; be. It is used internally by READ-VCARD.
(define (read-vcard-element . first-element?)
(let* [(first-element? (optional first-element? #f))
(line (read-folded-line (if first-element? 100 #f)))]
(cond
;; Ignore blank lines, theyre not doing anyone any harm!
[(or (string-null? line)
(irregex-search "^[[:whitespace:]]+$" line))
(read-vcard-element first-element?)]
;; If weve previously established this is a vCard stream were dealing
;; with, just go ahead and parse. If we havent established that, make
;; sure its a BEGIN:VCARD line first.
[(or (not first-element?)
(and first-element?
(string-contains line "BEGIN")
(string-contains line "VCARD")))
(parse-vcard-line (read-folded-line))]
;; If were still making sure the file is vCard, and the first non-blank
;; line *isnt* a BEGIN:VCARD line, then the file probably isnt a vCard.
[#t
(signal
(condition '(exn location vcarded message
"Not a valid vCard file.")
'(file)
'(vcard)))])))
;; Reader-thunk. Read a “logical” folded-line, where a line beginning with a
;; space is a continuation of the previous line — like with vcards.
(define (read-folded-line)
(let [(line (read-line))]
(if (eq? (peek-char) #\space)
(define (read-folded-line #!optional limit)
(let [(line (read-line (current-input-port) limit))]
(if (or (eq? (peek-char) #\space)
(eq? (peek-char) #\tab))
(string-concatenate
(list line
(string-drop (read-folded-line) 1)))