#lang scheme/base
(require "depend.ss"
"line.ss"
"phrase.ss"
(rename-in "kvs.ss"
(kvs-writertable header-writertable)
(kvs-writer-ref header-writer-ref)
)
(only-in "kvs.ss" kv->string kvs->string)
)
(define (header->string h)
(string-append (kv->string h
#:delim ": "
#:encode-val (header-writer-ref (car h) identity))
(line-term/string)))
(define (headers->string headers (end? #t))
(define (helper result)
(string-append result
(if end?
(line-term/string)
"")))
(helper (string-join (map header->string (kvs/list->kvlist headers)) "")))
(define (headers->input headers (end? #t))
(open-input-abytes (headers->string headers end?)))
(define (string->header line)
(define (helper match)
(if match
(let ((name (cadr match))
(value (caddr match)))
(cons name ((kvs-reader-ref name identity) value)))
#f))
(helper (regexp-match #px"^([^:]+)\\s*:\\s*(.+)$" line)))
(define p:header-field-char
(char-when (lambda (c)
(and (char<=? (integer->char 33) c (integer->char 126))
(not (char=? c #\:))))))
(define p:header-def
(seq header <- (one-many p:header-field-char)
(token #\:)
(return header)))
(define (read-header in)
(let-values (((v IN)
(p:header-def (make-input in))))
(if (failed? v) #f
(string->header (read-folded-line in)))))
(define (read-headers in)
(define (return headers)
(let-values (((v IN)
((bytes= (line-term/bytes)) (make-input in))))
(unless (failed? v)
(read-folded-line in)))
(reverse headers))
(define (helper headers)
(let ((header (read-header in)))
(if (not header) (return headers)
(helper (cons header headers)))))
(helper '()))
(provide/contract
(header->string (-> kv? string?))
(read-header (-> input-port? (or/c false/c kv?)))
(read-headers (-> input-port? kvs/list?))
(headers->string (->* (kvs/list?)
(boolean?)
string?))
(headers->input (->* (kvs/list?)
(boolean?)
input-port?))
)