;;;; ;;;; This file defines a dynamic string encapsulation called ;;;; "dstring". It simply stores the characters on a list in reverse ;;;; order making it easy for "cons" to append to the string. One ;;;; advantage of "dstring" over some alternatives is that calls to ;;;; "dstring->string" do not clear the current value.

;;;; ;;;; Another way to work around this problem is to use ;;;; "open-string-output-port" or "call-with-string-output-port" as ;;;; defined in R6RS, but these functions do not seem to be widely ;;;; implemented.

;;;; ;;;; Yet another way to work around the problem is to use string ports ;;;; from SLIB. Using "scm", it looks like the following: ;;;; ;;;; (require 'format) ;;;; (require 'string-port) ;;;; (define s (call-with-output-string ;;;; (lambda (s) ;;;; (format s ;;;; "~a~%~a~%" ;;;; "Hello, World!" ;;;; "Goodbye, Cruel World!")))) ;;;; ;;;; @author Paul Serice ;;;; ;;;; ;; This method returns a new, empty dynamic string. ;; ;; @return dstring (define (dstring) (let ((lst '())) ;; Return list of functions that have "lst" in lexical scope. (list ;; Get lst. (lambda () lst) ;; Set lst. (lambda (lst-new) (set! lst lst-new))))) ;;;; ;; Get the underlying list. ;; ;; @param[in] s dstring ;; @return underlying list (define (dstring-get-lst s) ((car s))) ;;;; ;; Set the underlying list. The list should hold the characters in ;; reverse order to match the way "cons" works. ;; ;; @param[in] s dstring ;; @param[in] lst new list of characters to use. ;; @return underlying list (define (dstring-set-lst s lst) ((cadr s) lst)) ;;;; ;; Return the conversion of the dstring "s" to a list. ;; ;; @param[in] s dstring ;; @return conversion of s to a list (define (dstring->list s) (reverse (dstring-get-lst s))) ;;;; ;; Return the conversion of the dstring "s" to a standard string. ;; ;; @param[in] s dstring ;; @return conversion of s to a standard string (define (dstring->string s) (list->string (dstring->list s))) ;;;; ;; The recursive portion of dstring-append. It prepends all the ;; characters in the "x" list to "accum" in reverse order. This could ;; be done with fold-left, but it is not widely available currently. ;; ;; @param[in] accum accumulated result ;; @param[in] x list of characters to prepend to x ;; @return accum with each character from x prepended to accum in reverse order (define (dstring-append/recursive accum x) (if (null? x) accum (dstring-append/recursive (cons (car x) accum) (cdr x)))) ;;;; ;; Append the standard string "x" to the dstring "s". ;; ;; @param[in] s dstring ;; @param[in] x standard string (define (dstring-append s x) (dstring-set-lst s (dstring-append/recursive (dstring-get-lst s) (string->list x)))) ;;;; ;; Append the character "c" to the dstring "s". ;; ;; @param[in] s dstring ;; @param[in] c character (define (dstring-append-char s c) (dstring-set-lst s (cons c (dstring-get-lst s)))) ;;;; ;; Append the optional standard string "(car args)" to the dstring "s" ;; then append the new-line character. ;; ;; @param[in] s dstring ;; @param[in] args optional standard string to append (define (dstring-append-line s . args) (if (not (null? args)) (dstring-append s (car args))) (dstring-append-char s #\newline)) ;;;; ;; Clear the dstring "s". (define (dstring-clear s) (dstring-set-lst s '()))