Eduardo Mu�oz <emufer@terra.es> wrote:
+---------------
| * Marco Antoniotti <marcoxa@cs.nyu.edu>
| | Does it mean that you are generating the full string in memory before
| | writing it out?
| | Do you have ways to control this behavior?
|
| htout does it too:
|
| * (with-html-output (*standard-output*) (:html (:h1 "Hi") (:p "foo"
| "bar" "baz")))
| <HTML><H1>Hi</H1><P>foobarbaz</P></HTML>
| NIL
| * (macroexpand '(with-html-output (*standard-output*) (:html (:h1 "Hi")
| (:p "foo" "bar" "baz"))))
| (LET ((*STANDARD-OUTPUT* *STANDARD-OUTPUT*))
| (WRITE-SEQUENCE "<HTML><H1>Hi</H1><P>foobarbaz</P></HTML>"
| *STANDARD-OUTPUT*)
| NIL)
+---------------
The problem with HTOUT [which I cheerfully continue to use anyway --
thanks, Tim!] is that it only does this aggregation if *ALL* of the
forms of the entire WITH-HTML-OUTPUT call result in constant strings.
Compare this with Edi Weitz's CL-WHO <URL:http://weitz.de/cl-who/>
[*very* similar to HTOUT], which tries to aggregate runs of constant
strings together [I'm using explicit package names here cuz I normally
have a (use-package :htout) in my init file]:
> (macroexpand
'(cl-who:with-html-output (*standard-output* *standard-output*
:prologue nil)
(:html (:h1 "Hi") (:p "foo" "bar" "baz"))))
(LET ((*STANDARD-OUTPUT* *STANDARD-OUTPUT*))
(PROGN
NIL
(WRITE-STRING "<html><h1>Hi</h1><p>foobarbaz</p></html>"
*STANDARD-OUTPUT*)))
T
>
The same as HTOUT so far, yes? [Except for the ":prologue nil" to
suppress the "<!DOCTYPE...>" that CL-WHO wants to put in for you
by default every time. Ugh.] Now let's add just one little STR call
to print a free string variable:
> (macroexpand
'(cl-who:with-html-output (*standard-output* *standard-output*
:prologue nil)
(:html (:h1 "Hi")
(:p "foo" (cl-who:str some-string-var) "bar" "baz"))))
(LET ((*STANDARD-OUTPUT* *STANDARD-OUTPUT*))
(PROGN
NIL
(WRITE-STRING "<html><h1>Hi</h1><p>foo" *STANDARD-OUTPUT*)
(PRINC SOME-STRING-VAR *STANDARD-OUTPUT*)
(WRITE-STRING "barbaz</p></html>" *STANDARD-OUTPUT*)))
T
>
Again, exactly what one would expect [or at least hope], yes?
Unfortunately, as noted above HTOUT doesn't do any aggregation at all if
it can't aggregate the entire macro call, and so just that one reference
to STR blows the code size up *way* out of sight [oops!]:
> (macroexpand
'(with-html-output (*standard-output*)
(:html (:h1 "Hi")
(:p "foo" (str some-string-var) "bar" "baz"))))
(LET ((*STANDARD-OUTPUT* *STANDARD-OUTPUT*))
(MACROLET ((HTM (&BODY ORG.TFEB.TML::FORMS)
`(WITH-HTML-OUTPUT (*STANDARD-OUTPUT* *STANDARD-OUTPUT* NIL)
,@ORG.TFEB.TML::FORMS))
(FMT (ORG.TFEB.TML::FORMAT-STRING &REST ORG.TFEB.TML::ARGS)
`(FORMAT *STANDARD-OUTPUT*
,ORG.TFEB.TML::FORMAT-STRING
,@ORG.TFEB.TML::ARGS))
(LFD (&OPTIONAL (ORG.TFEB.TML::N 1))
(IF (= ORG.TFEB.TML::N 1)
'(TERPRI *STANDARD-OUTPUT*)
`(LOOP ORG.TFEB.TML::REPEAT
,ORG.TFEB.TML::N
DO
(TERPRI *STANDARD-OUTPUT*))))
(ESC (STRING &OPTIONAL MAP)
(IF MAP
`(WRITE-SEQUENCE (ESCAPE-STRING ,STRING ,MAP)
*STANDARD-OUTPUT*)
`(WRITE-SEQUENCE (ESCAPE-STRING ,STRING)
*STANDARD-OUTPUT*)))
(STR (STRING)
`(WRITE-SEQUENCE ,STRING *STANDARD-OUTPUT*)))
(PROGN
(EMIT-TAG ':HTML *STANDARD-OUTPUT* :TYPE :OPEN)
(PROGN
(EMIT-TAG ':H1 *STANDARD-OUTPUT* :TYPE :OPEN)
(WRITE-SEQUENCE "Hi" *STANDARD-OUTPUT*)
(EMIT-TAG ':H1 *STANDARD-OUTPUT* :TYPE :CLOSE))
(PROGN
(EMIT-TAG ':P *STANDARD-OUTPUT* :TYPE :OPEN)
(WRITE-SEQUENCE "foo" *STANDARD-OUTPUT*)
(STR SOME-STRING-VAR)
(WRITE-SEQUENCE "bar" *STANDARD-OUTPUT*)
(WRITE-SEQUENCE "baz" *STANDARD-OUTPUT*)
(EMIT-TAG ':P *STANDARD-OUTPUT* :TYPE :CLOSE))
(EMIT-TAG ':HTML *STANDARD-OUTPUT* :TYPE :CLOSE))))
T
>
[The EMIT-TAGs are the generic functions HTOUT uses for the general cases.
All well and good, but it would be nice to do some more constant-string
aggregation around their occurences.]
That said, HTOUT is plenty fast for my current applications
(especially when compiled), so I haven't found a need yet to
convert to CL-WHO. (Yet...)
-Rob
-----
Rob Warnock, PP-ASEL-IA <rpw3@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607