escm - Embedded Scheme Processor

For version 1.1

escm is a filter program which takes a text with embedded Scheme exressions, copies it to the output with evaluating the Scheme expressions. You can use the power of Scheme to preprocess various text files, including CGI scripts.

I borrowed the idea from ePerl, embedded Perl language. Conceptually escm is the same as ePerl except that escm uses Scheme instead of Perl. In implementation level, however, escm is slightly different: the body of escm is a simple-minded preprocessor to convert the input text to a Scheme program, which then is evaluated by a Scheme interpreter to generate the final output. Because of this architecture, you can use your choice of Scheme implementation.

1. Getting Started

The last version of escm is 1.1: Tar+gzipped source . You can browse the document on line: Document.

You need Scheme installed on your system. I'm using STk. You can use any Scheme system as far as you can pipe Scheme expression into the interpreter and let it evaluate them.

  1. run ./configure
  2. The generated Makefile sets a default Scheme interpreter name. Edit it if you need to.
  3. run make to build the program.
  4. run make install to install.

2. Invoking escm

Synopsis

escm [-Ecv][-i interpreter][-o outfile][-e expr] [infile]

Options

Following options are recognized:

-E

Preprocess only. escm emits Scheme expressions which produce, if evaluated, the desirable output.

-c

CGI mode. In CGI mode, when escm encounters an error in preprocessing the input text, it generates an HTML page to report an error message and exit with zero status. Without this option, escm prints out an error message to stderr and exit with non-zero status, which is not desirable for CGI scripts.

-e expr

Pass the specified Scheme expression expr to the Scheme interpreter to be evaluated before processing the input text. You can give multiple -e options, and the expressions are passed in the order. At the time the expressions are evaluated, the preset variables (such as *escm-input-file*, described below) are already set.

-i interpreter

Specify the alternative Scheme interpreter to be used.

-o outfile

The output is written to outfile instead of stdout.

-v

Print escm version and exit.

Description

escm reads a text from infile, or stdin if it is not specified, and copies its contents to the outfile, or stdout if it is not specified. If infile contains the following sequences, escm interpretes them.

<? Scheme expressions ... !>

Evaluate Scheme expressions, and replaces this sequence to whatever the expressions prints out to stdout.

<?= Scheme expressions ... !>

Evaluate Scheme expressions, and replaces this sequence to the result of the last expression (using display).

In the scheme expressions, you can use whatever Scheme expressions the interpreter supports. Besides, the following Scheme variables are set for the convenience.

*escm-version*
A string to show the version of escm
*escm-input-file*
Input file name, if the input is specified in the command line; or #f when input is taken from stdin.
*escm-output-file*
Output file name, if the output is specified in the command line; #f otherwise.

The first few lines of the input may be treated specially.

No other fancier functions, like parsing CGI form parameters or generating HTTP headers, are provided by escm; it's beyond the scope of this small (a few hundred lines in C) program. Use the libraries of your own Scheme implementations.

The Scheme expressions needs not be complete inside single <?...!> construct. Rather, they can be mixed with the `literal' part of text freely, although the source may become a bit messy. For example, the following source produces either "FOO is true" or "FOO is not true", depends on the result of the evaluation of "(foo)".

<? (if (foo) (begin !>
FOO is true.
<?  ) (begin !>
FOO is not true.
<?  )) !>

Note that you need begin, since the literal text part may be translated into several Scheme forms by the preprocessor.

3. Example

This lists the contents of the directory, using some STk specific libraries. The second line explicitly specifies the Scheme interpreter (/usr/local/bin/snow) to be used.

#! /usr/local/bin/escm -c
#? /usr/local/bin/snow
Content-type: text/html

<html>
<head>
<title>Directory Listing</title>
</head>
<body bgcolor="#ffffff">
<h1>Directory Listing</h1>

<table>
<tr><th>File</th><th>Size</th><th>Modified</th></tr>
<?
(require "posix")

(do ((count 0 (+ count 1))
     (files (sort (glob ".*" "*") string<?) (cdr files)))
    ((null? files))
  (let* ((file (car files))
         (statv (posix-stat->vector (posix-stat file)))
         (color (if (odd? count) "bgcolor=\"#eeeeee\"" "bgcolor=\"#cccccc\"")))
    (display "<tr>")
    (if (file-is-directory? file)
        (format #t "<td ~a>~a/</td>~%" color file)
        (format #t "<td ~a><a href=~s>~a</a></td>~%" color file file))
    (format #t "<td ~a align=\"right\">~a</td>~%"
           color (vector-ref statv 6))                 ; size
    (format #t "<td ~a>~a</td>~%"
           color
           (posix-strftime "%Y/%m/%d %H:%M:%S HST"
             (posix-localtime (vector-ref statv 8))))  ; mtime
    ))
 !>
</table>
<p>(This list is generated by <b>escm <?=*escm-version*!></b>)</p>

</body>
</html>

Also take a look at escm.esc included in the tarball, which is a source of this html document.

Shiro Kawai, shiro@acm.org