#lang scheme/base
(require net/url
scheme/contract
srfi/26/cut
(file "../base.ss")
(file "struct.ss"))
(define NEWLINE-REGEXP #rx"[\r\n]")
(define QUOTE-REGEXP #rx"\"")
(define (csv->string csv)
(define out (open-output-string))
(display-csv csv out)
(get-output-string out))
(define (display-csv csv out)
(cond [(sheet? csv) (display-sheet csv out)]
[(row? csv) (display-row csv out)]
[(cell? csv) (display-cell csv out)]))
(define (display-sheet sheet out)
(let loop ([rows (sheet-rows sheet)])
(cond [(null? rows) (void)]
[(null? (cdr rows)) (display-row (car rows) out)]
[else (display-row (car rows) out)
(newline out)
(loop (cdr rows))])))
(define (display-row row out)
(let loop ([cells (row-cells row)])
(cond [(null? cells) (void)]
[(null? (cdr cells)) (display-cell (car cells) out)]
[else (display-cell (car cells) out)
(display #\, out)
(loop (cdr cells))])))
(define (display-cell cell out)
(define value (cell-value cell))
(cond [(boolean? value) (if value
(display "yes" out)
(display "no" out))]
[(number? value) (display value out)]
[(string? value) (display #\" out)
(display (escape-string-value value) out)
(display #\" out)]
[(symbol? value) (display #\" out)
(display (escape-string-value (symbol->string value)) out)
(display #\" out)]
[(bytes? value) (display #\" out)
(display (escape-string-value (bytes->string/utf-8 value)) out)
(display #\" out)]
[(url? value) (display #\" out)
(display (escape-string-value (url->string value)) out)
(display #\" out)]
[else (raise-exn exn:fail:contract
(format "Expected quotable-value, received ~s." value))]))
(define (escape-string-value value)
(regexp-replace* QUOTE-REGEXP (regexp-replace* NEWLINE-REGEXP value " \\n ") "\\\\\""))
(provide/contract
[csv->string (-> csv? string?)])