Skip to content

Instantly share code, notes, and snippets.

@gambiteer
Last active July 13, 2020 23:02
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gambiteer/06fd167594763a095c3e628bfbd37161 to your computer and use it in GitHub Desktop.
Save gambiteer/06fd167594763a095c3e628bfbd37161 to your computer and use it in GitHub Desktop.
(declare (standard-bindings)(extended-bindings)(block)(fixnum)(not safe))
;;; From Text-File Databases at https://sites.google.com/site/schemephil/
;;; READ-CSV-RECORD [SEP] [PORT]
(define (read-csv-record . args)
(define (add-char-to-field c field)
(let ((length (field-length field))
(buffer (field-buffer field)))
(if (< length (string-length buffer))
(begin
(string-set! buffer length c)
(field-length-set! field (+ length 1))
field)
(let ((new-buffer (string-append buffer (make-string length))))
(string-set! new-buffer length c)
(field-length-set! field (+ length 1))
(field-buffer-set! field new-buffer)
field))))
(define (extract-string-from-field! field)
(let ((result (substring (field-buffer field) 0 (field-length field))))
(reset-field! field)
result))
(define (new-field)
(cons (make-string 800)
0))
(define (field-buffer field)
(car field))
(define (field-buffer-set! field value)
(set-car! field value))
(define (field-length field)
(cdr field))
(define (field-length-set! field value)
(set-cdr! field value))
(define (reset-field! field)
(field-length-set! field 0)
field)
(define (add-field! field fields)
(cons (extract-string-from-field! field) fields))
(define (read-csv sep port)
(define (start field fields)
(let ((c (read-char port)))
(cond ((eof-object? c)
(reverse fields))
((char=? #\return c)
(carriage-return field fields))
((char=? #\newline c)
(line-feed field fields))
((char=? #\" c)
(quoted-field field fields))
((char=? sep c)
(let ((fields (add-field! field fields)))
(not-field field fields)))
(else
(unquoted-field (add-char-to-field c field) fields)))))
(define (not-field field fields)
(let ((c (read-char port)))
(cond ((eof-object? c)
(cons "" fields))
((char=? #\return c)
(carriage-return '() (add-field! field fields)))
((char=? #\newline c)
(line-feed '() (add-field! field fields)))
((char=? #\" c)
(quoted-field field fields))
((char=? sep c)
(let ((fields (add-field! field fields)))
(not-field field fields)))
(else
(unquoted-field (add-char-to-field c field) fields)))))
(define (quoted-field field fields)
(let ((c (read-char port)))
(cond ((eof-object? c)
(add-field! field fields))
((char=? #\" c)
(may-be-doubled-quotes field fields))
(else
(quoted-field (add-char-to-field c field) fields)))))
(define (may-be-doubled-quotes field fields)
(let ((c (read-char port)))
(cond ((eof-object? c)
(add-field! field fields))
((char=? #\return c)
(carriage-return '() (add-field! field fields)))
((char=? #\newline c)
(line-feed '() (add-field! field fields)))
((char=? #\" c)
(quoted-field (add-char-to-field #\" field) fields))
((char=? sep c)
(let ((fields (add-field! field fields)))
(not-field field fields)))
(else
(unquoted-field (add-char-to-field c field) fields)))))
(define (unquoted-field field fields)
(let ((c (read-char port)))
(cond ((eof-object? c)
(add-field! field fields))
((char=? #\return c)
(carriage-return '() (add-field! field fields)))
((char=? #\newline c)
(line-feed '() (add-field! field fields)))
((char=? sep c)
(let ((fields (add-field! field fields)))
(not-field field fields)) )
(else
(unquoted-field (add-char-to-field c field) fields)))))
(define (carriage-return field fields)
(if (char=? #\newline (peek-char port))
(read-char port))
fields)
(define (line-feed field fields)
(if (char=? #\return (peek-char port))
(read-char port))
fields)
(if (eof-object? (peek-char port))
(peek-char port)
(reverse (start (new-field) '()))))
(cond ((null? args)
(read-csv #\, (current-input-port)))
((and (null? (cdr args))
(char? (car args)))
(read-csv (car args) (current-input-port)))
((and (null? (cdr args))
(port? (car args)))
(read-csv #\, (car args)))
((and (pair? (cdr args)) (null? (cddr args))
(char? (car args)) (port? (cadr args)))
(read-csv (car args) (cadr args)))
(else
(car '()))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment