use @verbatim{...}

svn: r8699
This commit is contained in:
Eli Barzilay 2008-02-18 10:49:20 +00:00
parent 7e73623032
commit 9c77909710
25 changed files with 780 additions and 843 deletions

View File

@ -39,10 +39,9 @@ contain Scheme strings, and since escape characters are difficult for
people to read, a @litchar{|} character in @scheme[sexpr] is
converted to a @litchar{"} character before it is parsed. Thus,
@verbatim[#<<EOS
@verbatim{
<A MZSCHEME="|This goes nowhere.|">Nowhere</A>
EOS
]
}
creates a ``Nowhere'' hyperlink, which executes the Scheme program
@ -62,10 +61,9 @@ is executed immediately during HTML rendering. If the result is a
string, the comment is replaced in the input HTML stream with the
content of the string. Thus,
@verbatim[#<<EOS
@verbatim{
<!-- MZSCHEME="(format |<B>Here</B>: ~a| (current-directory))" -->
EOS
]
}
inserts the path of the current working directory into the containing
document (and ``Here'' is boldfaced). If the result is a snip instead

View File

@ -24,31 +24,34 @@
@title{@bold{Handin Server}}
@section{Handin-Server and Client}
The @scheme[handin-server] directory contains a server to be run by a course
instructor for accepting homework assignments and reporting on
The @scheme[handin-server] directory contains a server to be run by a
course instructor for accepting homework assignments and reporting on
submitted assignments.
The @scheme[handin-client] directory contains a client to be customized then
re-distributed to students in the course. The customized client will embed a
particular hostname and port where the server is running, as well as a server
certificate.
The @scheme[handin-client] directory contains a client to be
customized then re-distributed to students in the course. The
customized client will embed a particular hostname and port where the
server is running, as well as a server certificate.
With a customized client, students simply install a @filepath{.plt} file---so
there's no futzing with configuration dialogs and certificates. A student can
install any number of clients at once (assuming that the clients are properly
customized, as described below).
With a customized client, students simply install a @filepath{.plt}
file---so there's no futzing with configuration dialogs and
certificates. A student can install any number of clients at once
(assuming that the clients are properly customized, as described
below).
The result, on the student's side, is a @onscreen{Handin} button in DrScheme's
toolbar. Clicking the @onscreen{Handin} button allows the student to type a
password and upload the current content of the definitions and interactions
window to the course instructor's server. The @onscreen{File} menu is also
extended with a @onscreen{Manage...} menu item for managing a handin account
(i.e., changing the password and other information, or creating a new account
if the instructor configures the server to allow new accounts). Students can
submit joint work by submitting with a concatenation of usernames separated by
a ``@tt{+}''.
The result, on the student's side, is a @onscreen{Handin} button in
DrScheme's toolbar. Clicking the @onscreen{Handin} button allows the
student to type a password and upload the current content of the
definitions and interactions window to the course instructor's server.
The @onscreen{File} menu is also extended with a @onscreen{Manage...}
menu item for managing a handin account (i.e., changing the password
and other information, or creating a new account if the instructor
configures the server to allow new accounts). Students can submit
joint work by submitting with a concatenation of usernames separated
by a ``@tt{+}''.
On the instructor's side, the handin server can be configured to check
the student's submission before accepting it.
@ -62,119 +65,124 @@ server and each user's password.
@itemize{
@item{Create a new directory.}
@item{Copy @filepath{server-cert.pem} from the @filepath{handin-client} collection
to the new directory.
NOTE: For real use, you need a new certificate.
NOTE: See also @secref{wheres-the-collection}.}
@item{Copy @filepath{server-cert.pem} from the
@filepath{handin-client} collection to the new directory.
@item{Copy @filepath{private-key.pem} from the @filepath{handin-server} collection
to the new directory.
NOTE: For real use, you need a new key.}
NOTE: For real use, you need a new certificate.
NOTE: See also @secref{wheres-the-collection}.}
@item{Copy @filepath{private-key.pem} from the
@filepath{handin-server} collection to the new directory.
NOTE: For real use, you need a new key.}
@item{Create a file @filepath{users.ss} with the following content:
@schemeblock[
((tester ("8fe4c11451281c094a6578e6ddbf5eed"
"Tester" "1" "test@cs")))]}
@schemeblock[
((tester ("8fe4c11451281c094a6578e6ddbf5eed"
"Tester" "1" "test@cs")))]}
@item{Make a @filepath{test} subdirectory in your new directory.}
@item{Create a file @filepath{config.ss} with the following content:
@schemeblock[((active-dirs ("test")))]}
@schemeblock[((active-dirs ("test")))]}
@item{In your new directory, run
@commandline{mred -mvqM handin-server}}
@item{In your new directory, run @commandline{mred -l handin-server}}
@item{In the @filepath{handin-client} collection, edit @filepath{info.ss} and
uncomment the lines that define `server:port', @scheme[tools],
@scheme[tool-names], and @scheme[tool-icons].}
@item{In the @filepath{handin-client} collection, edit
@filepath{info.ss} and uncomment the lines that define
@scheme[server:port], @scheme[tools], @scheme[tool-names], and
@scheme[tool-icons].}
@item{Run
@commandline{setup-plt -l handin-client}
@item{Run @commandline{setup-plt -l handin-client}
NOTE: Under Windows, the executable is ``@tt{Setup PLT}''
instead of ``@tt{setup-plt}''.
NOTE: The command line arguments are optional.}
NOTE: Under Windows, the executable is ``@tt{Setup PLT}'' instead of
``@tt{setup-plt}''.
@item{Start DrScheme, click @onscreen{Handin} to run the client, submit with
username ``@tt{tester}'' and password ``@tt{pw}''.
NOTE: The command line arguments are optional.}
The submitted file will be @filepath{.../test/tester/handin.scm}.}
@item{Start DrScheme, click @onscreen{Handin} to run the client,
submit with username ``@tt{tester}'' and password ``@tt{pw}''.
The submitted file will be @filepath{.../test/tester/handin.scm}.}
@item{Check the status of your submission by pointing a web browser at
@tt{https://localhost:7980/servlets/status.ss}.
Note the ``s'' in ``https''. Use the ``@tt{tester}'' username and ``@tt{pw}''
password, as before.}
@tt{https://localhost:7980/servlets/status.ss}. Note the ``s'' in
``https''. Use the ``@tt{tester}'' username and ``@tt{pw}''
password, as before.}
}
@section[#:tag "wheres-the-collection"]{Where is the collection?}
If you obtained the server and client by installing a @filepath{.plt} file,
then the @filepath{handin-server} and @filepath{handin-client} directories
might be in your PLT addon space. Start MzScheme, and enter
@schemeblock[ (collection-path "handin-server") ]
@schemeblock[ (collection-path "handin-client") ]
If you obtained the server and client by installing a @filepath{.plt}
file, then the @filepath{handin-server} and @filepath{handin-client}
directories might be in your PLT addon space. Start MzScheme, and
enter
@schemeblock[(collection-path "handin-server")]
@schemeblock[(collection-path "handin-client")]
to find out where these collections are.
@section{Client Customization}
@itemize{
@item{Rename (or make a copy of) the @filepath{handin-client} collection
directory. The new name should describe your class uniquely.
For example, @filepath{uu-cpsc2010} is a good name for CPSC 2010 at the
University of Utah.}
@item{Rename (or make a copy of) the @filepath{handin-client}
collection directory. The new name should describe your class
uniquely. For example, @filepath{uu-cpsc2010} is a good name for CPSC
2010 at the University of Utah.}
@item{Edit the first three definitions of @filepath{info.ss} in your renamed
client collection:
@itemize{
@item{For @scheme[name], choose a name for the handin tool as it will
appear in DrScheme's interface (e.g., the @onscreen{XXX} for the
@onscreen{Manage XXX Handin Account...} menu item). Again, make the
name specific to the course, in case a student installs
multiple handin tools. Do not use @onscreen{Handin} as the last part
of the name, since @onscreen{Handin} is always added for button and
menu names.}
@item{Edit the first three definitions of @filepath{info.ss} in your
renamed client collection:
@itemize{
@item{For @scheme[name], choose a name for the handin tool as it
will appear in DrScheme's interface (e.g., the @onscreen{XXX} for
the @onscreen{Manage XXX Handin Account...} menu item). Again,
make the name specific to the course, in case a student installs
multiple handin tools. Do not use @onscreen{Handin} as the last
part of the name, since @onscreen{Handin} is always added for
button and menu names.}
@item{Uncomment the definitions of @scheme[tools],
@scheme[tool-names], and @scheme[tool-icons].}
@item{Uncomment the definitions of @scheme[tools],
@scheme[tool-names], and @scheme[tool-icons].}
@item{For @scheme[server:port], uncomment the line, and use the hostname
and port where the server will be running to accept handin
submissions.}
}
Optionally uncomment and edit the next two definitions,
@scheme[web-menu-name] and @scheme[web-address], to add an item to the @onscreen{Help}
menu that opens a (course-specific) web page.}
@item{For @scheme[server:port], uncomment the line, and use the
hostname and port where the server will be running to accept
handin submissions.}}
@item{ Replace @filepath{icon.png} in your renamed directory with a new 32x32
icon. This icon is displayed on startup with DrScheme's splash
screen, and it is included at half size on the @onscreen{Handin} button.
Again, choose a distinct icon for the benefit of students who
install multiple handin tools. A school logo is typically
useful, as it provides a recognizably local visual cue.}
Optionally uncomment and edit the next two definitions,
@scheme[web-menu-name] and @scheme[web-address], to add an item to
the @onscreen{Help} menu that opens a (course-specific) web page.}
@item{ Replace @filepath{server-cert.pem} in your renamed directory with a
server certificate. The file @filepath{server-cert.pem} in
@filepath{handin-client} collection is ok for testing, but the point of
this certificate is to make handins secure, so you should
generate a new (self-certifying) certificate and keep its key
private. (See @secref{server-setup}.)}
@item{Replace @filepath{icon.png} in your renamed directory with a new
32x32 icon. This icon is displayed on startup with DrScheme's
splash screen, and it is included at half size on the
@onscreen{Handin} button. Again, choose a distinct icon for the
benefit of students who install multiple handin tools. A school
logo is typically useful, as it provides a recognizably local visual
cue.}
@item{ Run
@commandline{mzc --collection-plt <name>.plt <name>}
where @tt{<name>} is the name that you chose for your directory
(i.e., whatever you changed @filepath{handin-client} to).}
@item{Replace @filepath{server-cert.pem} in your renamed directory
with a server certificate. The file @filepath{server-cert.pem} in
@filepath{handin-client} collection is ok for testing, but the point
of this certificate is to make handins secure, so you should
generate a new (self-certifying) certificate and keep its key
private. (See @secref{server-setup}.)}
@item{Run @commandline{mzc --collection-plt <name>.plt <name>} where
@tt{<name>} is the name that you chose for your directory (i.e.,
whatever you changed @filepath{handin-client} to).}
@item{Distribute @filepath{<name>.plt} to students for installation
into their copies of DrScheme. The students need not have access to
the DrScheme installation directory; the tool will be installed on
the filesystem in the student's personal space. If you want to
install it once on a shared installation, use setup-plt with the
@DFlag{all-users} flag.}
@item{ Distribute @filepath{<name>.plt} to students for installation into their
copies of DrScheme. The students need not have access to the
DrScheme installation directory; the tool will be installed on
the filesystem in the student's personal space. If you want to
install it once on a shared installation, use setup-plt with the
@DFlag{all-users} flag.}
}
@section[#:tag "server-setup"]{Server Setup}
You must prepare a special directory to host the handin server. To
@ -183,362 +191,353 @@ set the @envvar{PLT_HANDINSERVER_DIR} environment variable.
This directory contains the following files and sub-directories:
@itemize{
@item{@filepath{server-cert.pem} : the server's certificate. To create a
certificate and key with openssl:
@item{@filepath{server-cert.pem}: the server's certificate. To create
a certificate and key with openssl:
@commandline{openssl req -new -nodes -x509 -days 365
-out server-cert.pem -keyout private-key.pem}}
@commandline{openssl req -new -nodes -x509 -days 365 -out server-cert.pem -keyout private-key.pem}
}
@item{@filepath{private-key.pem} : the private key to go with
@filepath{server-cert.pem}. Whereas @filepath{server-cert.pem} gets distributed to
students with the handin client, @filepath{private-key.pem} is kept
private.}
@item{@filepath{private-key.pem}: the private key to go with
@filepath{server-cert.pem}. Whereas @filepath{server-cert.pem} gets
distributed to students with the handin client,
@filepath{private-key.pem} is kept private.}
@item{@filepath{config.ss} : configuration options. The file format is
@item{@filepath{config.ss}: configuration options. The file format is
@schemeblock[((<key> <val>) ...)]
@schemeblock[ ((<key> <val>) ...)]
The following keys can be used:
The following keys can be used:
@itemize{
@item{@indexed-scheme[active-dirs] --- a list of directories that
are active submissions, relative to the current directory or
absolute; the last path element for each of these (and
@scheme[inactive-dirs] below) should be unique, and is used to
identify the submission (for example, in the client's submission
dialog and in the status servlet).}
@comment{I took out the quote before each identifier.}
@itemize{
@item{@indexed-scheme[active-dirs] --- a list of directories that are active
submissions, relative to the current directory or absolute;
the last path element for each of these (and @scheme['inactive-dirs]
below) should be unique, and is used to identify the
submission (for example, in the client's submission dialog
and in the status servlet).}
@item{@indexed-scheme[inactive-dirs] --- a list of inactive
submission directories (see above for details).}
@item{@indexed-scheme[inactive-dirs] --- a list of inactive submission directories (see
above for details).}
@item{@indexed-scheme[port-number] --- the port for the main handin
server; the default is 7979.}
@item{@indexed-scheme[port-number] --- the port for the main handin server; the default
is 7979.}
@item{@indexed-scheme[https-port-number] --- the port number for the
handin-status HTTPS server; the default is @scheme[#f] which
indicates that no HTTPS server is started.}
@item{@indexed-scheme[https-port-number] --- the port number for the handin-status HTTPS
server; the default is @scheme[#f] which indicates that no HTTPS
server is started.}
@item{@indexed-scheme[session-timeout] --- number of seconds before
the session times-out. The client is given this many seconds for
the login stage and then starts again so the same number of
seconds is given for the submit-validation process; the default is
300.}
@item{@indexed-scheme[session-timeout] --- number of seconds before the session
times-out. The client is given this many seconds for the
login stage and then starts again so the same number of
seconds is given for the submit-validation process; the
default is 300.}
@item{@indexed-scheme[session-memory-limit] --- maximum size in
bytes of memory allowed for per-session computation, if
per-session limits are supported (i.e., when using MrEd and
MzScheme with the (default) exact garbage collector and memory
accounting); the default is 40000000.}
@item{@indexed-scheme[session-memory-limit] --- maximum size in bytes of memory allowed
for per-session computation, if per-session limits are
supported (i.e., when using MrEd3m and MzScheme3m with memory
accounting); the default is 40000000.}
@item{@indexed-scheme[default-file-name] --- the default filename
that will be saved with the submission contents. The default is
@filepath{handin.scm}.}
@item{@indexed-scheme[default-file-name] --- the default filename that will be saved
with the submission contents. The default is @filepath{handin.scm}.}
@item{@indexed-scheme[max-upload] --- maximum size in bytes of an
acceptable submission; the default is 500000.}
@item{@indexed-scheme[max-upload] --- maximum size in bytes of an acceptable submission;
the default is 500000.}
@item{@indexed-scheme[max-upload-keep] --- maximum index of
submissions to keep; the most recent submission is
@filepath{handin.scm} (by default), the next oldest is in
@filepath{BACKUP-0/handin.scm}, next oldest is
@filepath{BACKUP-1/handin.scm}, etc. The default is 9.}
@item{@indexed-scheme[max-upload-keep] --- maximum index of submissions to keep; the
most recent submission is @filepath{handin.scm} (by default), the next
oldest is in @filepath{BACKUP-0/handin.scm}, next oldest is
@filepath{BACKUP-1/handin.scm}, etc. The default is 9.}
@item{@indexed-scheme[user-regexp] --- a regular expression that is
used to validate usernames; alternatively, this can be @scheme[#f]
meaning no restriction, or a list of permitted strings. Young
students often choose exotic usernames that are impossible to
remember, and forget capitalization, so the default is fairly
strict--- @scheme[#rx"^[a-z][a-z0-9]+$"]; a @scheme["+"] is always
disallowed in a username, since it is used in a submission
username to specify joint work.}
@item{@indexed-scheme[user-regexp] --- a regular expression that is used to validate usernames;
alternatively, this can be @scheme[#f] meaning no restriction, or a list of
permitted strings. Young students often choose exotic usernames that
are impossible to remember, and forget capitalization, so the default
is fairly strict--- @scheme[#rx"^[a-z][a-z0-9]+$"]; a @scheme["+"] is
always disallowed in a username, since it is used in a submission
username to specify joint work.}
@item{@indexed-scheme[user-desc] --- a plain-words description of
the acceptable username format (according to user-regexp above);
@scheme[#f] stands for no description; the default is
@scheme["alphanumeric string"] which matches the default
user-regexp.}
@item{@indexed-scheme[user-desc] --- a plain-words description of the acceptable
username format (according to user-regexp above); @scheme[#f] stands
for no description; the default is @scheme["alphanumeric string"]
which matches the default user-regexp.}
@item{@indexed-scheme[username-case-sensitive] --- a boolean; when
@scheme[#f], usernames are case-folded for all purposes; defaults
to @scheme[#f] (note that you should not set this to @scheme[#t]
on Windows or when using other case-insensitive filesystems, since
usernames are used as directory names).}
@item{@indexed-scheme[username-case-sensitive] --- a boolean; when @scheme[#f], usernames are
case-folded for all purposes; defaults to @scheme[#f] (note that you
should not set this to @scheme[#t] on Windows or when using other
case-insensitive filesystems, since usernames are used as
directory names).}
@item{@indexed-scheme[allow-new-users] --- a boolean indicating
whether to allow new-user requests from a client tool; the default
is @scheme[#f].}
@item{@indexed-scheme[allow-new-users] --- a boolean indicating whether to allow
new-user requests from a client tool; the default is @scheme[#f].}
@item{@indexed-scheme[allow-change-info] --- a boolean indicating
whether to allow changing user information from a client tool
(changing passwords is always possible); the default is
@scheme[#f].}
@item{@indexed-scheme[allow-change-info] --- a boolean indicating whether to allow
changing user information from a client tool (changing
passwords is always possible); the default is @scheme[#f].}
@item{@indexed-scheme[master-password] --- a string for an MD5 hash
for a password that allows login as any user; the default is
@scheme[#f], which disables the password.}
@item{@indexed-scheme[master-password] --- a string for an MD5 hash for a password that
allows login as any user; the default is @scheme[#f], which disables
the password.}
@item{@indexed-scheme[log-output] --- a boolean that controls
whether the handin server log is written on the standard output;
defaults to @scheme[#t].}
@item{@indexed-scheme[log-output] --- a boolean that controls whether the handin server
log is written on the standard output; defaults to @scheme[#t].}
@item{@indexed-scheme[log-file] --- a path (relative to handin
server directory or absolute) that specifies a filename for the
handin server log (possibly combined with the @scheme[log-output]
option), or @scheme[#f] for no log file; defaults to
@filepath{log}.}
@item{@indexed-scheme[log-file] --- a path (relative to handin server directory or
absolute) that specifies a filename for the handin server log
(possibly combined with the 'log-output option), or @scheme[#f] for
no log file; defaults to @filepath{log}.}
@item{@indexed-scheme[web-base-dir] --- if @scheme[#f] (the
default), the built-in web server will use the
@filepath{status-web-root} in this collection for its
configuration; to have complete control over the built in server,
you can copy and edit @filepath{status-web-root}, and add this
configuration entry with the name of your new copy (relative to
the handin server directory, or absolute).}
@item{@indexed-scheme[web-base-dir] --- if @scheme[#f] (the default), the built-in web server
will use the @filepath{status-web-root} in this collection for its
configuration; to have complete control over the built in
server, you can copy and edit @filepath{status-web-root}, and add this
configuration entry with the name of your new copy (relative
to the handin server directory, or absolute).}
@item{@indexed-scheme[web-log-file] --- a path (relative to handin
server directory or absolute) that specifies a filename for
logging the internal HTTPS status web server; or @scheme[#f] (the
default) to disable this log.}
@item{@indexed-scheme[web-log-file] --- a path (relative to handin server directory or
absolute) that specifies a filename for logging the internal
HTTPS status web server; or @scheme[#f] (the default) to disable
this log.}
@item{@indexed-scheme[extra-fields] --- a list that describes extra
string fields of information for student records; each element in
this list is a list of three values: the name of the field, the
regexp (or @scheme[#f], or a list of permitted string values), and
a string describing acceptable strings. The default is
@schemeblock[
'(("Full Name" #f #f)
("ID#" #f #f)
("Email" #rx"^[^@<>\"`',]+@[a-zA-Z0-9_.-]+[.][a-zA-Z]+$"
"a valid email address"))]
You can set this to a list of fields that you are interested in
keeping, for example:
@schemeblock[
'(("Full Name"
#rx"^[A-Z][a-zA-Z]+(?: [A-Z][a-zA-Z]+)+$"
"full name, no punctuations, properly capitalized")
("Utah ID Number"
#rx"^[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]$"
"Utah ID Number with exactly nine digits")
("Email"
#rx"^[^@<>\"`',]+@cs\\.utah\\.edu$"
"A Utah CS email address"))]
The order of these fields will be used both on the client GUI side
and in the @filepath{users.ss} file (see below).
@item{@indexed-scheme[extra-fields] --- a list that describes extra string fields of
information for student records; each element in this list is
a list of three values -- the name of the field, the regexp
(or @scheme[#f], or a list of permitted string values), and a string
describing of acceptable strings. The default is
@schemeblock[
'(("Full Name" #f #f)
("ID#" #f #f)
("Email" #rx"^[^@<>\"`',]+@[a-zA-Z0-9_.-]+[.][a-zA-Z]+$"
"a valid email address"))]
@comment{a hyperlink here for users.ss?}
You can set this to a list of fields that you are interested
in keeping, for example:
The second item in a field description can also be the symbol
@scheme['-], which marks this field as one that is hidden from the
user interface: students will not see it and will not be able to
provide or modify it; when a new student creates an account, such
fields will be left empty. This is useful for adding information
that you have on students from another source, for example, adding
information from a course roster. You should manually edit the
@filepath{users.ss} file and fill in such information. (The third
element for such descriptors is ignored.)}
@schemeblock[
'(("Full Name"
#rx"^[A-Z][a-zA-Z]+(?: [A-Z][a-zA-Z]+)+$"
"full name, no punctuations, properly capitalized")
("Utah ID Number"
#rx"^[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]$"
"Utah ID Number with exactly nine digits")
("Email"
#rx"^[^@<>\"`',]+@cs\\.utah\\.edu$"
"A Utah CS email address"))]
@item{@indexed-scheme[hook-file] --- a path (relative to handin
server directory or absolute) that specifies a filename that
contains a `hook' module. This is useful as a general device for
customizing the server through Scheme code. The file is expected
to contain a module that provides a @scheme[hook] function, which
should be receiving three arguments:
The order of these fields will be used both on the client GUI
side and in the @filepath{users.ss} file (see below).
@declare-exporting[#:use-sources (handin-server/scribblings/hook-dummy)]
@comment{a hyperlink here for users.ss?}
@defproc[(hook [operation symbol?]
[connection-context (or/c number? symbol? false?)]
[relevant-info (listof (list/c symbol? any))])
void?]{
The second item in a field description can also be the symbol
@scheme['-], which marks this field as one that is hidden from the
user interface: students will not see it and will not be able
to provide or modify it; when a new student creates an
account, such fields will be left empty. This is useful for
adding information that you have on students from another
source, for example, adding information from a course roster.
You should manually edit the @filepath{users.ss} file and fill in such
information. (The third element for such descriptors is
ignored.)}
The @scheme[operation] argument indicates the operation that is
now taking place. It can be one of the following:
@indexed-scheme['server-start],
@indexed-scheme['server-connect], @indexed-scheme['user-create],
@indexed-scheme['user-change], @indexed-scheme['login],
@indexed-scheme['submission-received],
@indexed-scheme['submission-committed],
@indexed-scheme['submission-retrieved],
@indexed-scheme['status-login], or
@indexed-scheme['status-file-get].
@item{@indexed-scheme[hook-file] --- a path (relative to handin server directory or
absolute) that specifies a filename that contains a `hook'
module. This is useful as a general device for customizing
the server through Scheme code. The file is expected to
contain a module that provides a @scheme[hook] function, which
should be receiving three arguments:
The @scheme[connection-context] argument is a datum that
specifies the connection context (a number for handin
connections, a @scheme['wN] symbol for servlet connections, and
@scheme[#f] for other server operations).
The @scheme[relevant-info] contains an alist of information
relevant to this operation. Currently, the hook is used in
several places after an operation has completed.
For example, here is a simple hook module that sends
notification messages when users are created or their
information has changed:
@declare-exporting[#:use-sources (handin-server/scribblings/hook-dummy)]
@schememod[
mzscheme
(provide hook)
(require (lib "sendmail.ss" "net"))
(define (hook what session alist)
(when (memq what '(user-create user-change))
(send-mail-message
"course-staff@university.edu"
(format "[server] ~a (~a)" what session)
'("course-staff@university.edu") '() '()
(map (lambda (key+val) (apply format "~a: ~s" key+val))
alist))))]}}}
@comment{should the result be void?}
@defproc[(hook [operation symbol?] [connection-context (or/c number? symbol? false?)]
[relevant-info (listof (list/c symbol? any))])
any/c]{
Changes to @filepath{config.ss} are detected, the file will be
re-read, and options are reloaded. A few options are fixed at
startup time: port numbers, log file specs, and the
@scheme[web-base-dir] are as configured at startup. All other
options will change the behavior of the running server (but things
like @scheme[username-case-sensitive?] it would be unwise to do
so). (For safety, options are not reloaded until the file parses
correctly, but make sure that you don't save a copy that has
inconsistent options: it is best to create a new configuration file
and move it over the old one, or use an editor that does so and not
save until the new contents is ready.) This is most useful for
closing & opening submissions directories.}
The @scheme[operation] argument indicates the operation that is now
taking place. It can be one of the following:
@indexed-scheme['server-start], @indexed-scheme['server-connect],
@indexed-scheme['user-create], @indexed-scheme['user-change], @indexed-scheme['login],
@indexed-scheme['submission-received], @indexed-scheme['submission-committed],
@indexed-scheme['submission-retrieved], @indexed-scheme['status-login],
or @indexed-scheme['status-file-get].
@item{@filepath{users.ss} (created if not present if a user is added):
keeps the list of user accounts, along with the associated password
(actually the MD5 hash of the password), and extra string fields as
specified by the 'extra-fields configuration entry (in the same
order). The file format is
@schemeblock{
((<username-sym> (<pw-md5-str> <extra-field> ...))
...)}
The @scheme[connection-context] argument is a datum
that specifies the connection context (a number for handin
connections, a @scheme['wN] symbol for servlet connections,
and @scheme[#f] for other server operations).
The @scheme[relevant-info] contains an alist of information relevant
to this operation. Currently, the hook is used in several places
after an operation has completed.
For example, the default @scheme['extra-field] setting will make this:
@schemeblock{
((<username-sym> (<pw-md5-str> <full-name> <id> <email>))
...)}
For example, here is a simple hook module that sends
notification messages when users are created or their information has
changed:
Usernames that begin with ``solution'' are special. They are used by the
HTTPS status server. Independent of the @scheme['user-regexp] and
@scheme['username-case-sensitive?] configuration items, usernames are not
allowed to contain characters that are illegal in Windows pathnames, and they
cannot end or begin in spaces or periods.
@schemeblock[
(module hook mzscheme
(provide hook)
(require (lib "sendmail.ss" "net"))
(define (hook what session alist)
(when (memq what '(user-create user-change))
(send-mail-message
"course-staff@university.edu"
(format "[server] ~a (~a)" what session)
'("course-staff@university.edu") '() '()
(map (lambda (key+val)
(apply format "~a: ~s" key+val))
alist)))))]
If the @scheme['allow-new-users] configuration allows new users, the
@filepath{users.ss} file can be updated by the server with new
users. It can always be updated by the server to change passwords.
Changes to @filepath{config.ss} are detected, the file will be re-read, and
options are reloaded. A few options are fixed at startup time:
port numbers, log file specs, and the @scheme[web-base-dir] are as
configured at startup. All other options will change the behavior
of the running server (but things like @scheme[username-case-sensitive?]
it would be unwise to do so). (For safety, options are not
reloaded until the file parses correctly, but make sure that you
don't save a copy that has inconsistent options: it is best to
create a new configuration file and move it over the old one, or
use an editor that does so and not save until the new contents is
ready.) This is most useful for closing & opening submissions
directories.}}}
}
@item{@filepath{users.ss} (created if not present if a user is added) : keeps
the list of user accounts, along with the associated password
(actually the MD5 hash of the password), and extra string fields
as specified by the 'extra-fields configuration entry (in the same
order). The file format is
If you have access to a standard Unix password file (from
@filepath{/etc/passwd} or @filepath{/etc/shadow}), then you can
construct a @filepath{users.ss} file that will allow users to use
their normal passwords. To achieve this, use a list with 'unix as
the first element and the system's encrypted password string as the
second element. Such passwords can be used, but when users change
them, a plain md5 hash will be used.
@schemeblock{
((<username-sym> (<pw-md5-str> <extra-field> ...))
...)
}
You can combine this with other fields from the password file to
create your @filepath{users.ss}, but make sure you have information
that matches your 'extra-fields specification. For example, given
this system file:
@verbatim{
foo:wRzN1u5q2SqRD:1203:1203:L.E. Foo :/home/foo:/bin/tcsh
bar:$1$dKlU0OkJ$t63TzKz:1205:1205:Bar Z. Lie:/home/bar:/bin/bash}
you can create this @filepath{users.ss} file:
@schemeblock[
((foo ((unix "wRzN1u5q2SqRD") "L.E. Foo" "?"))
(bar ((unix "$1$dKlU0OkJ$t63TzKz") "Bar Z. Lie" "?")))]
which can be combined with this setting for @scheme['extra-fields]
in your @filepath{config.ss}:
@schemeblock[
...
(extra-fields (("Full Name" #f #f)
("TA" '("Alice" "Bob") "Your TA")))
...]
and you can tell your students to use their department username and
password, and use the @onscreen{Manage ...} dialog to properly set
their TA name.
For example, the default @scheme['extra-field] setting will make this:
Finally, a password value can be a list that begins with a
@scheme['plaintext] symbol, which will be used without encryption.
This may be useful for manually resetting a forgotten passwords.}
@schemeblock{
((<username-sym> (<pw-md5-str> <full-name> <id> <email>))
...)
}
@item{@filepath{log} (or any other name that the @scheme['log-file]
configuration option specifies (if any), created if not present,
appended otherwise): records connections and actions, where each
entry is of the form
@verbatim{[<id>|<time>] <msg>}
where @scheme[<id>] is an integer representing the connection
(numbered consecutively from 1 when the server starts), ``@tt{-}''
for a message without a connection, and ``@tt{wN}'' for a message
from the status servlet.}
Usernames that begin with ``solution'' are special. They are used by the
HTTPS status server. Independent of the @scheme['user-regexp] and
@scheme['username-case-sensitive?] configuration items, usernames are not
allowed to contain characters that are illegal in Windows pathnames, and they
cannot end or begin in spaces or periods.
@item{Active and inactive assignment directories (which you can put in
a nested directory for convenience, or specify a different absolute
directory), as specified by the configuration file using the
@scheme['active-dirs] and @scheme['inactive-dirs]. A list of active
assignment directories (the last path element in each specified path
is used as a label) is sent to the client tool when a student clicks
@onscreen{Handin}. The assignment labels are ordered in the
student's menu using @scheme[string<?], and the first assignment is
the default selection.
If the @scheme['allow-new-users] configuration allows new users, the
@filepath{users.ss} file can be updated by the server with new users. It can
always be updated by the server to change passwords.
Within each assignment directory, the student id is used for a
sub-directory name. Within each student sub-directory are
directories for handin attempts and successes. If a directory
@filepath{ATTEMPT} exists, it contains the most recent (unsuccessful
or currently-in-submission) handin attempt. Directories
@filepath{SUCCESS-n} (where n counts from 0) contain successful
handins; the lowest numbered such directory represents the latest
handin.
If you have access to a standard Unix password file (from
@filepath{/etc/passwd} or @filepath{/etc/shadow}), then you can construct a
@filepath{users.ss} file that will allow users to use their normal
passwords. To achieve this, use a list with 'unix as the first
element and the system's encrypted password string as the second
element. Such passwords can be used, but when users change them,
a plain md5 hash will be used.
A cleanup process in the server copies successful submissions to the
student directory, one level up from the corresponding
@filepath{SUCCESS-n} directory. This is done only for files and
directories that are newer in @filepath{SUCCESS-n} than in the
submission root, other files and directories are left intact. If
external tools add new content to the student directory (e.g., a
@filepath{grade} file, as described below) it will stay there. If
the machine crashes or the server is stopped, the cleanup process
might not finish. When the server is started, it automatically runs
the cleanup process for each student directory.
You can combine this with other fields from the password file to
create your @filepath{users.ss}, but make sure you have information that
matches your 'extra-fields specification. For example, given this
system file:
Within a student directory, a @filepath{handin.scm} file (or some
other name if the @scheme[default-file-name] option is set) contains
the actual submission. A @scheme[checker] procedure can change this
default file name, and it can create additional files in an
@filepath{ATTEMPT} directory (to be copied by the cleanup process);
see below for more details on @schememodname[handin-server/checker].
@verbatim[
"foo:wRzN1u5q2SqRD:1203:1203:L.E. Foo:/home/foo:/bin/tcsh
bar:$1$dKlU0OkJ$t63TzKz:1205:1205:Bar Z. Lie:/home/bar:/bin/bash"]
For submissions from a normal DrScheme frame, a submission file
contains a copy of the student's definitions and interactions
windows. The file is in a binary format (to support non-text code),
and opening the file directly in DrScheme shows the definitions
part. To get both the definitions and interactions parts, the file
can be parsed with @scheme[unpack-submission] from
@schememodname[handin-server/utils].
you can create this @filepath{users.ss} file:
To submit an assignment as a group, students use a concatenation of
usernames separated by ``@tt{+}'' and any number of spaces (e.g.,
``@tt{user1+user2}''). The same syntax (``@tt{user1+user2}'') is
used for the directory for shared submissions, where the usernames
are always sorted so that directory names are deterministic.
Multiple submissions for a particular user in different groups will
be rejected.
@schemeblock[
((foo ((unix "wRzN1u5q2SqRD") "L.E. Foo" "?"))
(bar ((unix "$1$dKlU0OkJ$t63TzKz") "Bar Z. Lie" "?")))]
Inactive assignment directories are used by the the HTTPS status web
server.}
which can be combined with this setting for 'extra-fields in your
@filepath{config.ss}:
@schemeblock[
...
(extra-fields (("Full Name" #f #f)
("TA" '("Alice" "Bob") "Your TA")))
...]
and you can tell your students to use their department username
and password, and use the @onscreen{Manage ...} dialog to properly set
their TA name.
Finally, a password value can be a list that begins with a
@scheme['plaintext] symbol, which will be used without encryption. This
may be useful for manually resetting a forgotten passwords.
}
@item{@filepath{log} (or any other name that the 'log-file configuration option
specifies (if any), created if not present, appended otherwise)
: records connections and actions, where each entry is of the
form
@verbatim[
"(id time-str msg-str)
[<id>|<time>] <msg>}"]
where @scheme[<id>] is an integer representing the connection (numbered
consecutively from 1 when the server starts), ``@tt{-}'' for a message
without a connection, and ``@tt{wN}'' for a message from the status
servlet.}
@item{Active and inactive assignment directories (which you can put in a
nested directory for convenience, or specify a different absolute
directory), as specified by the configuration file using the
`active-dirs' and `inactive-dirs'. A list of active assignment
directories (the last path element in each specified path is used
as a label) is sent to the client tool when a student clicks
@onscreen{Handin}. The assignment labels are ordered in the student's menu
using @scheme[string<?], and the first assignment is the default
selection.
Within each assignment directory, the student id is used for a
sub-directory name. Within each student sub-directory are
directories for handin attempts and successes. If a directory
@filepath{ATTEMPT} exists, it contains the most recent (unsuccessful or
currently-in-submission) handin attempt. Directories @filepath{SUCCESS-n}
(where n counts from 0) contain successful handins; the lowest
numbered such directory represents the latest handin.
A cleanup process in the server copies successful submissions to
the student directory, one level up from the corresponding
@filepath{SUCCESS-n} directory. This is done only for files and
directories that are newer in @filepath{SUCCESS-n} than in the submission
root, other files and directories are left intact. If external
tools add new content to the student directory (eg, a @filepath{grade}
file, as described below) it will stay there. If the machine
crashes or the server is stopped, the cleanup process might not
finish. When the server is started, it automatically runs the
cleanup process for each student directory.
Within a student directory, a @filepath{handin.scm} file (or some other
name if the @scheme[default-file-name] option is set) contains the actual
submission. A @scheme[checker] procedure can change this default file
name, and it can create additional files in an @filepath{ATTEMPT} directory
(to be copied by the cleanup process); see below for more details
on @schememodname[handin-server/checker].
For submissions from a normal DrScheme frame, a submission file
contains a copy of the student's definitions and interactions
windows. The file is in a binary format (to support non-text
code), and opening the file directly in DrScheme shows the
definitions part. To get both the definitions and interactions
parts, the file can be parsed with @scheme[unpack-submission] from
@schememodname[handin-server/utils].
To submit an assignment as a group, students use a concatenation
of usernames separated by ``@tt{+}'' and any number of spaces (e.g.,
``@tt{user1+user2}''). The same syntax (``@tt{user1+user2}'') is used for the
directory for shared submissions, where the usernames are always
sorted so that directory names are deterministic. Multiple
submissions for a particular user in different groups will be
rejected.
Inactive assignment directories are used by the the HTTPS status
web server.}
@item{@filepath{<active-assignment>/checker.ss} (optional) : a module that
exports a @scheme[checker] function. This function receives two
@comment{use defproc here?}
arguments: a username list and a submission as a byte string.
(See also @scheme[unpack-submission], etc. from @schememodname[handin-server/utils].) To
@item{@filepath{<active-assignment>/checker.ss} (optional): a module
that exports a @scheme[checker] function. This function receives
two
@; use defproc here?
arguments: a username list and a submission as a byte string. (See
also @scheme[unpack-submission], etc. from
@schememodname[handin-server/utils].) To
reject the submission, the @scheme[checker] function can raise an
exception; the exception message will be relayed back to the
student. The module is loaded when the current directory is the
@ -568,7 +567,7 @@ bar:$1$dKlU0OkJ$t63TzKz:1205:1205:Bar Z. Lie:/home/bar:/bin/bash"]
The checker should return a string, such as @filepath{handin.scm}, to use
in naming the submission file, or @scheme[#f] to indicate that he file
should be deleted (eg, when the checker alrady created the
should be deleted (e.g., when the checker alrady created the
submission file(s) in a different place).
Alternatively, the module can bind @scheme[checker] to a list of three
@ -665,6 +664,7 @@ to obtain a list of all assignments, or
to start with a specific assignment (named ASSIGNMENT). The default
PORT is 7980.
@section{Checker Utilities}
The checker utilities are provided to make writing checker functions.
@ -692,6 +692,7 @@ common submission situations.}}
The following sections describe each of these modules.
@section{Sandbox}
@defmodule[handin-server/sandbox]
@ -699,6 +700,7 @@ The following sections describe each of these modules.
This is just a wrapper around the sandbox engine from MzLib. It configures it
for use with the handin server.
@section{Utils}
@defmodule[handin-server/utils]
@ -877,6 +879,7 @@ Checks whether @scheme[name] is defined in the evaluator @scheme[eval], and
#f)]. (Note that before the checker is used (after the pre-checker, if
specified), the timer will be reset to the @scheme['session-timeout] value.)}
@section{checker}
@defmodulelang[handin-server/checker]{
@ -1189,7 +1192,7 @@ values from the submission code.
information includes only execution coverage by submission code, excluding
additional checker tests. You do not have to call this explicitly---it is
called at the end of the process automatically when @scheme[:coverage?] is
enabled. It is made available so you can call it earlier (eg, before
enabled. It is made available so you can call it earlier (e.g., before
testing) to show clients a coverage error first, or if you want to avoid an
error. For example, you can do this:
@ -1206,6 +1209,7 @@ values from the submission code.
}
}
@section[#:tag "multi-file"]{Multiple-File Submissions}
By default, the system is set up for submissions of single a single
@ -1221,7 +1225,7 @@ submissions, do the following:
suffix that should be used for the single concatenated output file.}
@item{You can also add a @scheme[:names-checker] keyword--the value can be a
regexp that all submitted files must follow (eg, @scheme[".*[.]scm$"]), or a
regexp that all submitted files must follow (e.g., @scheme[".*[.]scm$"]), or a
list of expected file names. Alternatively, it can be a 1-argument
procedure that will receive the (sorted) list of submitted files and
can throw an error if some files are missing or some files are
@ -1258,6 +1262,7 @@ submission utility---the resulting executable can be used outside of
DrScheme (but PLT Scheme is still required, so it cannot be
uninstalled).
@section{Auto-Updater}
The handin-client has code that can be used for automatic updating of

View File

@ -48,16 +48,14 @@ re-exported by @schememodname[net/url].}
The basic structure for all URLs, hich is explained in RFC 3986
@cite["RFC3986"]. The following diagram illustrates the parts:
@verbatim[#<<EOS
@verbatim|{
http://sky@www:801/cgi-bin/finger;xyz?name=shriram;host=nw#top
{-1} {2} {3} {4}{---5-------------} {----7-------------} {8}
{6}
{-1} {2} {3} {4}{---5---------} {6} {----7-------------} {8}
1 = scheme, 2 = user, 3 = host, 4 = port,
5 = path (two elements), 6 = param (of second path element),
7 = query, 8 = fragment
EOS
]
}|
The strings inside the @scheme[user], @scheme[path], @scheme[query],
and @scheme[fragment] fields are represented directly as Scheme

View File

@ -634,7 +634,7 @@ control can be placed into struct fields.
As an example, consider the following C code:
@verbatim[#<<EOS
@verbatim{
typedef struct { int x; char y; } A;
typedef struct { A a; int z; } B;
@ -656,8 +656,7 @@ As an example, consider the following C code:
char gety(A* a) {
return a->y;
}
EOS
]
}
Using the simple @scheme[_list-struct], you might expect this code to
work:

View File

@ -330,8 +330,7 @@ The built-in container classes include horizontal panels (and panes),
vertical containers, a programmer can achieve most any layout. For
example, we can construct a dialog with the following shape:
@verbatim[
#<<IMG
@verbatim{
------------------------------------------------------
| ------------------------------------- |
| Your name: | | |
@ -340,8 +339,7 @@ The built-in container classes include horizontal panels (and panes),
| ( Cancel ) ( OK ) |
| -------- ---- |
------------------------------------------------------
IMG
]
}
with the following program:

View File

@ -21,7 +21,7 @@ When @exec{mzscheme} is run with no command-line arguments (other than
confguration options, like @Flag{j}), then it starts a @tech{REPL}
with a @litchar{> } prompt:
@verbatim[" Welcome to MzScheme\n > "]
@verbatim{ Welcome to MzScheme\n > }
@margin-note{For information on GNU Readline support, see
@schememodname[readline/rep].}

View File

@ -18,12 +18,11 @@ executable followed by a module declaration. For example, if
@exec{mzscheme} is installed in @filepath{/usr/local/bin}, then a file
containing the following text acts as a ``hello world'' script:
@verbatim[#<<EOS
@verbatim{
#! /usr/local/bin/mzscheme
#lang scheme/base
"Hello, world!"
EOS
]
}
In particular, if the above is put into a file @filepath{hello} and
the file is made executable (e.g., with @exec{chmod a+x hello}), then
@ -40,23 +39,21 @@ executable, a popular alternative is to require that @exec{mzscheme}
is in the user's command path, and then ``trampoline'' using
@exec{/usr/bin/env}:
@verbatim[#<<EOS
@verbatim{
#! /usr/bin/env mzscheme
#lang scheme/base
"Hello, world!"
EOS
]
}
In either case, command-line arguments to a script are available via
@scheme[current-command-line-arguments]:
@verbatim[#<<EOS
@verbatim{
#! /usr/bin/env mzscheme
#lang scheme/base
(printf "Given arguments: ~s\n"
(current-command-line-arguments))
EOS
]
}
If the name of the script is needed, it is available via
@scheme[(find-system-path 'run-file)], instead of via
@ -68,7 +65,7 @@ them using the @scheme[command-line] form provided by
command-line arguments from @scheme[(current-command-line-arguments)]
by default:
@verbatim[#<<EOS
@verbatim{
#! /usr/bin/env mzscheme
#lang scheme
@ -84,8 +81,7 @@ by default:
(printf "~a~a\n"
greeting
(if (verbose?) " to you, too!" ""))
EOS
]
}
Try running the above script with the @DFlag{help} flag to see what
command-line arguments are allowed by the script.
@ -95,7 +91,7 @@ that are comments in one language and expressions in the other. This
trampoline is more complicated, but it provides more control over
command-line arguments to @scheme{mzscheme}:
@verbatim[#<<EOS
@verbatim|{
#! /bin/sh
#|
exec mzscheme -cu "$0" ${1+"$@"}
@ -105,8 +101,7 @@ command-line arguments to @scheme{mzscheme}:
(printf "bytecode files has been disabled via -c.\n")
(printf "Given arguments: ~s\n"
(current-command-line-arguments))
EOS
]
}|
Note that @litchar{#!} starts a line comment in Scheme, and
@litchar{#|}...@litchar{|#} forms a block comment. Meanwhile,

View File

@ -41,11 +41,10 @@ The @var{f} function is called by the custodian if it is ever asked to
``shutdown'' its values; @var{o} and @var{data} are passed on to
@var{f}, which has the type
@verbatim[#<<EOS
@verbatim{
typedef void (*Scheme_Close_Custodian_Client)(Scheme_Object *o,
void *data);
EOS
]
}
If @var{strong} is non-zero, then the newly managed value will
be remembered until either the custodian shuts it down or
@ -85,13 +84,12 @@ Installs a function to be called on each custodian-registered item and
its closer when MzScheme is about to exit. The registered function
has the type
@verbatim[#<<EOS
@verbatim{
typedef
void (*Scheme_Exit_Closer_Func)(Scheme_Object *o,
Scheme_Close_Custodian_Client *f,
void *d);
EOS
]
}
where @var{d} is the second argument for @var{f}.}

View File

@ -58,7 +58,7 @@ For example, consider the following implementation of a
performs @scheme[or] on the results of the thunks, evaluating only as
many thunks as necessary.
@verbatim[#<<EOS
@verbatim{
static Scheme_Object *
thunk_or (int argc, Scheme_Object **argv)
{
@ -74,8 +74,7 @@ thunk_or (int argc, Scheme_Object **argv)
return scheme_tail_apply(argv[argc - 1], 0, NULL);
}
EOS
]
}
This @scheme[thunk-or] properly implements tail-recursion: if the
final thunk is applied, then the result of @scheme[thunk-or] is the

View File

@ -18,7 +18,7 @@ in @cpp{scheme_current_thread->error_buf}. The macro
@cppi{scheme_error_buf} is a shorthand for
@cpp{*scheme_current_thread->error_buf}.
@verbatim[#<<EOS
@verbatim{
mz_jmp_buf * volatile save, fresh;
...
save = scheme_current_thread->error_buf;
@ -31,8 +31,7 @@ in @cpp{scheme_current_thread->error_buf}. The macro
}
scheme_current_thread->error_buf = save;
...
EOS
]
}
3m: when @cpp{scheme_setjmp} is used, the enclosing context must
provide a local-variable registration record via @cpp{MZ_GC_DECL_REG}.
@ -85,7 +84,7 @@ visible when implementing a new primitive procedure. When
request by chaining to the previously saved error buffer; otherwise,
call @cppi{scheme_clear_escape}.
@verbatim[#<<EOS
@verbatim{
mz_jmp_buf * volatile save, fresh;
save = scheme_current_thread->error_buf;
scheme_current_thread->error_buf = &fresh;
@ -102,8 +101,7 @@ call @cppi{scheme_clear_escape}.
scheme_eval_string("x", scheme_env);
}
scheme_current_thread->error_buf = save;
EOS
]
}
This solution works fine as long as the procedure implementation only
calls top-level evaluation functions (@cpp{scheme_eval},
@ -122,97 +120,95 @@ exceptions in a variety of situations. It implements the function
application of a thunk. (This code is in
@filepath{collects/mzscheme/examples/catch.c} in the distribution.)
@verbatim[#<<EOS
static Scheme_Object *exn_catching_apply, *exn_p, *exn_message;
@verbatim{
static Scheme_Object *exn_catching_apply, *exn_p, *exn_message;
static void init_exn_catching_apply()
{
if (!exn_catching_apply) {
char *e =
"(lambda (thunk) "
"(with-handlers ([void (lambda (exn) (cons #f exn))]) "
"(cons #t (thunk))))";
/* make sure we have a namespace with the standard bindings: */
Scheme_Env *env = (Scheme_Env *)scheme_make_namespace(0, NULL);
static void init_exn_catching_apply()
{
if (!exn_catching_apply) {
char *e =
"(lambda (thunk) "
"(with-handlers ([void (lambda (exn) (cons #f exn))]) "
"(cons #t (thunk))))";
/* make sure we have a namespace with the standard bindings: */
Scheme_Env *env = (Scheme_Env *)scheme_make_namespace(0, NULL);
scheme_register_extension_global(&exn_catching_apply,
sizeof(Scheme_Object *));
scheme_register_extension_global(&exn_p,
sizeof(Scheme_Object *));
scheme_register_extension_global(&exn_message,
sizeof(Scheme_Object *));
exn_catching_apply = scheme_eval_string(e, env);
exn_p = scheme_lookup_global(scheme_intern_symbol("exn?"), env);
exn_message
= scheme_lookup_global(scheme_intern_symbol("exn-message"),
env);
scheme_register_extension_global(&exn_catching_apply,
sizeof(Scheme_Object *));
scheme_register_extension_global(&exn_p,
sizeof(Scheme_Object *));
scheme_register_extension_global(&exn_message,
sizeof(Scheme_Object *));
exn_catching_apply = scheme_eval_string(e, env);
exn_p = scheme_lookup_global(scheme_intern_symbol("exn?"), env);
exn_message
= scheme_lookup_global(scheme_intern_symbol("exn-message"),
env);
}
}
/* This function applies a thunk, returning the Scheme value if
there's no exception, otherwise returning NULL and setting *exn
to the raised value (usually an exn structure). */
Scheme_Object *_apply_thunk_catch_exceptions(Scheme_Object *f,
Scheme_Object **exn)
{
Scheme_Object *v;
init_exn_catching_apply();
v = _scheme_apply(exn_catching_apply, 1, &f);
/* v is a pair: (cons #t value) or (cons #f exn) */
if (SCHEME_TRUEP(SCHEME_CAR(v)))
return SCHEME_CDR(v);
else {
*exn = SCHEME_CDR(v);
return NULL;
}
}
Scheme_Object *extract_exn_message(Scheme_Object *v)
{
init_exn_catching_apply();
if (SCHEME_TRUEP(_scheme_apply(exn_p, 1, &v)))
return _scheme_apply(exn_message, 1, &v);
else
return NULL; /* Not an exn structure */
}
}
/* This function applies a thunk, returning the Scheme value if
there's no exception, otherwise returning NULL and setting *exn
to the raised value (usually an exn structure). */
Scheme_Object *_apply_thunk_catch_exceptions(Scheme_Object *f,
Scheme_Object **exn)
{
Scheme_Object *v;
init_exn_catching_apply();
v = _scheme_apply(exn_catching_apply, 1, &f);
/* v is a pair: (cons #t value) or (cons #f exn) */
if (SCHEME_TRUEP(SCHEME_CAR(v)))
return SCHEME_CDR(v);
else {
*exn = SCHEME_CDR(v);
return NULL;
}
}
Scheme_Object *extract_exn_message(Scheme_Object *v)
{
init_exn_catching_apply();
if (SCHEME_TRUEP(_scheme_apply(exn_p, 1, &v)))
return _scheme_apply(exn_message, 1, &v);
else
return NULL; /* Not an exn structure */
}
EOS
]
In the following example, the above code is used to catch exceptions
that occur during while evaluating source code from a string.
@verbatim[#<<EOS
static Scheme_Object *do_eval(void *s, int noargc, Scheme_Object **noargv)
{
return scheme_eval_string((char *)s, scheme_get_env(scheme_config));
@verbatim{
static Scheme_Object *do_eval(void *s, int noargc, Scheme_Object **noargv)
{
return scheme_eval_string((char *)s, scheme_get_env(scheme_config));
}
static Scheme_Object *eval_string_or_get_exn_message(char *s)
{
Scheme_Object *v, *exn;
v = scheme_make_closed_prim(do_eval, s);
v = _apply_thunk_catch_exceptions(v, &exn);
/* Got a value? */
if (v)
return v;
v = extract_exn_message(exn);
/* Got an exn? */
if (v)
return v;
/* `raise' was called on some arbitrary value */
return exn;
}
}
static Scheme_Object *eval_string_or_get_exn_message(char *s)
{
Scheme_Object *v, *exn;
v = scheme_make_closed_prim(do_eval, s);
v = _apply_thunk_catch_exceptions(v, &exn);
/* Got a value? */
if (v)
return v;
v = extract_exn_message(exn);
/* Got an exn? */
if (v)
return v;
/* `raise' was called on some arbitrary value */
return exn;
}
EOS
]
@; ----------------------------------------------------------------------
@section{Enabling and Disabling Breaks}

View File

@ -206,39 +206,36 @@ pointer within a function call at any point when a collection can be
triggered. Beware that nested function calls can hide temporary
pointers; for example, in
@verbatim[#<<EOS
@verbatim{
scheme_make_pair(scheme_make_pair(scheme_true, scheme_false),
scheme_make_pair(scheme_false, scheme_true))
EOS
]
}
the result from one @cpp{scheme_make_pair} call is on the stack or in
a register during the other call to @cpp{scheme_make_pair}; this
pointer must be exposed to the garbage collection and made subject to
update. Simply changing the code to
@verbatim[#<<EOS
@verbatim{
tmp = scheme_make_pair(scheme_true, scheme_false);
scheme_make_pair(tmp,
scheme_make_pair(scheme_false, scheme_true))
EOS
]
}
does not expose all pointers, since @cpp{tmp} must be evaluated before
the second call to @cpp{scheme_make_pair}. In general, the above code
must be converted to the form
@verbatim[#<<EOS
@verbatim{
tmp1 = scheme_make_pair(scheme_true, scheme_false);
tmp2 = scheme_make_pair(scheme_true, scheme_false);
scheme_make_pair(tmp1, tmp2);
EOS
]
}
and this is converted form must be instrumented to register @cpp{tmp1}
and @cpp{tmp2}. The final result might be
@verbatim[#<<EOS
@verbatim{
{
Scheme_Object *tmp1 = NULL, *tmp2 = NULL, *result;
MZ_GC_DECL_REG(2);
@ -255,8 +252,7 @@ and @cpp{tmp2}. The final result might be
return result;
}
EOS
]
}
Notice that @cpp{result} is not registered above. The
@cpp{MZ_GC_UNREG} macro cannot trigger a garbage collection, so the
@ -273,7 +269,7 @@ whereas registering an array of pointers requires three slots. For
example, to register a pointer @cpp{tmp} and an array of 10
@cpp{char*}s:
@verbatim[#<<EOS
@verbatim{
{
Scheme_Object *tmp1 = NULL;
char *a[10];
@ -288,8 +284,7 @@ example, to register a pointer @cpp{tmp} and an array of 10
f(a);
...
}
EOS
]
}
The @cppi{MZ_GC_ARRAY_VAR_IN_REG} macro registers a local array given
a starting slot, the array variable, and an array size. The
@ -305,7 +300,7 @@ must be registered with the collector during the entire call to
The name used for a variable need not be immediate. Structure members
can be supplied as well:
@verbatim[#<<EOS
@verbatim{
{
struct { void *s; int v; void *t; } x = {NULL, 0, NULL};
MZ_GC_DECL_REG(2);
@ -314,8 +309,7 @@ can be supplied as well:
MZ_GC_VAR_IN_REG(0, x.t);
...
}
EOS
]
}
In general, the only constraint on the second argument to
@cppi{MZ_GC_VAR_IN_REG} or @cppi{MZ_GC_ARRAY_VAR_IN_REG} is that
@ -336,7 +330,7 @@ example also illustrates how @cpp{MZ_GC_UNREG} is not needed when
control escapes from the function, such as when
@cpp{scheme_signal_error} escapes.
@verbatim[#<<EOS
@verbatim{
{
Scheme_Object *tmp1 = NULL, *tmp2 = NULL;
mzchar *a, *b;
@ -371,15 +365,14 @@ control escapes from the function, such as when
return tmp1;
}
EOS
]
}
A @cpp{MZ_GC_DECL_REG} can be used in a nested block to hold
declarations for the block's variables. In that case, the nested
@cpp{MZ_GC_DECL_REG} must have its own @cpp{MZ_GC_REG} and
@cpp{MZ_GC_UNREG} calls.
@verbatim[#<<EOS
@verbatim{
{
Scheme_Object *accum = NULL;
MZ_GC_DECL_REG(1);
@ -403,8 +396,7 @@ declarations for the block's variables. In that case, the nested
MZ_GC_UNREG();
return accum;
}
EOS
]
}
Variables declared in a local block can also be registered together
with variables from an enclosing block, but the local-block variable
@ -412,7 +404,7 @@ must be unregistered before it goes out of scope. The
@cppi{MZ_GC_NO_VAR_IN_REG} macro can be used to unregister a variable
or to initialize a slot as having no variable.
@verbatim[#<<EOS
@verbatim{
{
Scheme_Object *accum = NULL;
MZ_GC_DECL_REG(2);
@ -435,8 +427,7 @@ or to initialize a slot as having no variable.
MZ_GC_UNREG();
return accum;
}
EOS
]
}
The @cpp{MZ_GC_} macros all expand to nothing when @cpp{MZ_PRECISE_GC}
is not defined, so the macros can be placed into code to be compiled
@ -536,23 +527,22 @@ The following macros can be used (with care!) to navigate
Example:
@verbatim[#<<EOS
int foo(int c, ...) {
int r = 0;
XFORM_START_SKIP;
{
/* va plays strange tricks that confuse xform */
va_list args;
va_start(args, c);
while (c--) {
r += va_arg(args, int);
@verbatim{
int foo(int c, ...) {
int r = 0;
XFORM_START_SKIP;
{
/* va plays strange tricks that confuse xform */
va_list args;
va_start(args, c);
while (c--) {
r += va_arg(args, int);
}
}
XFORM_END_SKIP;
return r;
}
XFORM_END_SKIP;
return r;
}
EOS
]
These macros can also be used at the top level, outside of any
function. Since they have to be terminated by a semi-colon, however,
@ -565,21 +555,20 @@ EOS
Example:
@verbatim[#<<EOS
int foo(int c, ...) {
int r = 0;
{
/* va plays strange tricks that confuse xform */
XFORM_CAN_IGNORE va_list args; /* See below */
XFORM_HIDE_EXPR(va_start(args, c));
while (c--) {
r += XFORM_HIDE_EXPR(va_arg(args, int));
@verbatim{
int foo(int c, ...) {
int r = 0;
{
/* va plays strange tricks that confuse xform */
XFORM_CAN_IGNORE va_list args; /* See below */
XFORM_HIDE_EXPR(va_start(args, c));
while (c--) {
r += XFORM_HIDE_EXPR(va_arg(args, int));
}
}
return r;
}
}
return r;
}
EOS
]}
}}
@item{@cppi{XFORM_CAN_IGNORE}: a macro that acts like a type
modifier (must appear first) to indicate that a declared variable
@ -710,14 +699,13 @@ Overrides the GC's auto-determined stack base, and/or disables the
The following example shows a typical use for setting the stack base:
@verbatim[#<<EOS
@verbatim{
int main(int argc, char **argv) {
int dummy;
scheme_set_stack_base(&dummy, 0);
real_main(argc, argv); /* calls scheme_basic_env(), etc. */
}
EOS
]}
}}
@function[(void scheme_set_stack_bounds
[void* stack_addr]
@ -789,7 +777,7 @@ finalizers are registered for @var{p}.
The @cpp{fnl_proc} type is not actually defined, but it is equivalent
to
@verbatim[" typedef void (*fnl_proc)(void *p, void *data)"]
@verbatim{ typedef void (*fnl_proc)(void *p, void *data)}
The @var{f} argument is the callback function; when it is called, it
will be passed the value @var{p} and the data pointer @var{data};
@ -908,12 +896,11 @@ Forces an immediate garbage-collection.}
Each of the three procedures takes a pointer and returns an integer:
@verbatim[#<<EOS
@verbatim{
typedef int (*Size_Proc)(void *obj);
typedef int (*Mark_Proc)(void *obj);
typedef int (*Fixup_Proc)(void *obj);
EOS
]
}
If the result of the size procedure is a constant, then pass a
non-zero value for @var{is_const_size}. If the mark and fixup

View File

@ -168,7 +168,7 @@ tables) can be anything.
The public portion of the @cppi{Scheme_Hash_Table} type is defined
roughly as follows:
@verbatim[#<<EOS
@verbatim{
typedef struct Scheme_Hash_Table {
Scheme_Object so; /* so.type == scheme_hash_table_type */
/* ... */
@ -180,8 +180,7 @@ roughly as follows:
int (*compare)(void *v1, void *v2);
/* ... */
} Scheme_Hash_Table;
EOS
]
}
The @cpp{make_hash_indices} and @cpp{compare} function pointers can be
set to arbitrary hashing and comparison functions (before any mapping
@ -235,7 +234,7 @@ two are the same as for hash tables. The last is like
The public portion of the @cppi{Scheme_Bucket_Table} type is defined
roughly as follows:
@verbatim[#<<EOS
@verbatim{
typedef struct Scheme_Bucket_Table {
Scheme_Object so; /* so.type == scheme_variable_type */
/* ... */
@ -246,8 +245,7 @@ roughly as follows:
int (*compare)(void *v1, void *v2);
/* ... */
} Scheme_Bucket_Table;
EOS
]
}
The @cpp{make_hash_indices} and @cpp{compare} functions are used as
for hash tables. Note that @cppi{SCHEME_hash_weak_ptr} supplied as the
@ -288,15 +286,14 @@ Returns the current value for @var{key} in @var{table}, or @cpp{NULL}
Returns the bucket for @var{key} in @var{table}. The
@cppi{Scheme_Bucket} structure is defined as:
@verbatim[#<<EOS
@verbatim{
typedef struct Scheme_Bucket {
Scheme_Object so; /* so.type == scheme_bucket_type */
/* ... */
void *key;
void *val;
} Scheme_Bucket;
EOS
]
}
Setting @var{val} to @cpp{NULL} unmaps the bucket's key, and @var{key}
can be @cpp{NULL} in that case as well. If the table holds keys

View File

@ -78,14 +78,13 @@ the global variable is undefined.
The @cppi{Scheme_Bucket} structure is defined as:
@verbatim[#<<EOS
@verbatim{
typedef struct Scheme_Bucket {
Scheme_Object so; /* so.type = scheme_variable_type */
void *key;
void *val;
} Scheme_Bucket;
EOS
]}
}}
@function[(Scheme_Bucket* scheme_module_bucket
[Scheme_Object* mod]

View File

@ -160,7 +160,7 @@ registered using @cppi{scheme_register_extension_global} (see
As an example, the following C code defines an extension that returns
@scheme["hello world"] when it is loaded:
@verbatim[#<<EOS
@verbatim{
#include "escheme.h"
Scheme_Object *scheme_initialize(Scheme_Env *env) {
return scheme_make_utf8_string("hello world");
@ -171,8 +171,7 @@ As an example, the following C code defines an extension that returns
Scheme_Object *scheme_module_name() {
return scheme_false;
}
EOS
]
}
Assuming that this code is in the file @filepath{hw.c}, the extension
is compiled under Unix with the following two commands:
@ -323,7 +322,7 @@ evaluates all expressions provided on the command line and displays
the results, then runs a @scheme[read]-@scheme[eval]-@scheme[print]
loop:
@verbatim[#<<EOS
@verbatim{
#include "scheme.h"
int main(int argc, char *argv[])
@ -358,8 +357,7 @@ int main(int argc, char *argv[])
}
return 0;
}
EOS
]
}
Under Mac OS X, or under Windows when MzScheme is compiled to a DLL
using Cygwin, the garbage collector cannot find static variables
@ -432,7 +430,7 @@ The simple embedding program from the previous section can be
extended to work with either CGC or 3m, dependong on whether
@cpp{MZ_PRECISE_GC} is specified on the compiler's command line:
@verbatim[#<<EOS
@verbatim{
#include "scheme.h"
int main(int argc, char *argv[])
@ -487,8 +485,7 @@ int main(int argc, char *argv[])
return 0;
}
EOS
]
}
Strictly speaking, the @cpp{config} and @cpp{v} variables above need not be
registered with the garbage collector, since their values are not needed

View File

@ -47,11 +47,10 @@ substantial or unbounded work should occasionally call
Creates a primitive procedure value, given the C function pointer
@var{prim}. The form of @var{prim} is defined by:
@verbatim[#<<EOS
@verbatim{
typedef Scheme_Object *(Scheme_Prim)(int argc,
Scheme_Object **argv);
EOS
]
}
The value @var{mina} should be the minimum number of arguments that
must be supplied to the procedure. The value @var{maxa} should be the
@ -95,13 +94,12 @@ in @var{vals}; when the C function @var{prim} is invoked, the
generated primitive is passed as the last parameter. The form of
@var{prim} is defined by:
@verbatim[#<<EOS
@verbatim{
typedef
Scheme_Object *(Scheme_Prim_Closure_Proc)(int argc,
Scheme_Object **argv,
Scheme_Object *prim);
EOS
]
}
The macro @cppi{SCHEME_PRIM_CLOSURE_ELS} takes a primitive-closure
object and returns an array with the same length and content as
@ -119,12 +117,11 @@ Creates an old-style primitive procedure value; when the C function
@var{prim} is invoked, @var{data} is passed as the first parameter.
The form of @var{prim} is defined by:
@verbatim[#<<EOS
@verbatim{
typedef
Scheme_Object *(Scheme_Closed_Prim)(void *data, int argc,
Scheme_Object **argv);
EOS
]}
}}
@function[(Scheme_Object* scheme_make_closed_prim
[Scheme_Closed_Prim* prim]

View File

@ -85,23 +85,22 @@ of ``fuel'' that has been consumed since the last call to
@scheme[vector->list] consumes a unit of fuel for each created cons
cell:
@verbatim[#<<EOS
Scheme_Object *scheme_vector_to_list(Scheme_Object *vec)
{
int i;
Scheme_Object *pair = scheme_null;
@verbatim{
Scheme_Object *scheme_vector_to_list(Scheme_Object *vec)
{
int i;
Scheme_Object *pair = scheme_null;
i = SCHEME_VEC_SIZE(vec);
i = SCHEME_VEC_SIZE(vec);
for (; i--; ) {
SCHEME_USE_FUEL(1);
pair = scheme_make_pair(SCHEME_VEC_ELS(vec)[i], pair);
for (; i--; ) {
SCHEME_USE_FUEL(1);
pair = scheme_make_pair(SCHEME_VEC_ELS(vec)[i], pair);
}
return pair;
}
return pair;
}
EOS
]
The @cpp{SCHEME_USE_FUEL} macro expands to a C block, not an
expression.
@ -174,42 +173,41 @@ class. (Any regular event-loop-based callback is appropriate.) The
@cpp{scheme_notify_multithread} pointer is set to
@cpp{MrEdInstallThreadTimer}. (MrEd no longer work this way, however.)
@verbatim[#<<EOS
class MrEdThreadTimer : public wxTimer
{
public:
void Notify(void); /* callback when timer expires */
};
@verbatim{
class MrEdThreadTimer : public wxTimer
{
public:
void Notify(void); /* callback when timer expires */
};
static int threads_go;
static MrEdThreadTimer *theThreadTimer;
#define THREAD_WAIT_TIME 40
static int threads_go;
static MrEdThreadTimer *theThreadTimer;
#define THREAD_WAIT_TIME 40
void MrEdThreadTimer::Notify()
{
if (threads_go)
Start(THREAD_WAIT_TIME, TRUE);
void MrEdThreadTimer::Notify()
{
if (threads_go)
Start(THREAD_WAIT_TIME, TRUE);
scheme_check_threads();
scheme_check_threads();
}
static void MrEdInstallThreadTimer(int on)
{
if (!theThreadTimer)
theThreadTimer = new MrEdThreadTimer;
if (on)
theThreadTimer->Start(THREAD_WAIT_TIME, TRUE);
else
theThreadTimer->Stop();
threads_go = on;
if (on)
do_this_time = 1;
}
}
static void MrEdInstallThreadTimer(int on)
{
if (!theThreadTimer)
theThreadTimer = new MrEdThreadTimer;
if (on)
theThreadTimer->Start(THREAD_WAIT_TIME, TRUE);
else
theThreadTimer->Stop();
threads_go = on;
if (on)
do_this_time = 1;
}
EOS
]
An alternate architecture, which MrEd now uses, is to send the main
thread into a loop, which blocks until an event is ready to handle.
Scheme automatically takes care of running all threads, and it does so
@ -242,84 +240,83 @@ ready on any of those file descriptors, the callbacks are removed and
For example, the X Windows version of MrEd formerly set
@cpp{scheme_wakeup_on_input} to this @cpp{MrEdNeedWakeup}:
@verbatim[#<<EOS
static XtInputId *scheme_cb_ids = NULL;
static int num_cbs;
@verbatim{
static XtInputId *scheme_cb_ids = NULL;
static int num_cbs;
static void MrEdNeedWakeup(void *fds)
{
int limit, count, i, p;
fd_set *rd, *wr, *ex;
static void MrEdNeedWakeup(void *fds)
{
int limit, count, i, p;
fd_set *rd, *wr, *ex;
rd = (fd_set *)fds;
wr = ((fd_set *)fds) + 1;
ex = ((fd_set *)fds) + 2;
rd = (fd_set *)fds;
wr = ((fd_set *)fds) + 1;
ex = ((fd_set *)fds) + 2;
limit = getdtablesize();
limit = getdtablesize();
/* See if we need to do any work, really: */
count = 0;
for (i = 0; i < limit; i++) {
if (MZ_FD_ISSET(i, rd))
count++;
if (MZ_FD_ISSET(i, wr))
count++;
if (MZ_FD_ISSET(i, ex))
count++;
/* See if we need to do any work, really: */
count = 0;
for (i = 0; i < limit; i++) {
if (MZ_FD_ISSET(i, rd))
count++;
if (MZ_FD_ISSET(i, wr))
count++;
if (MZ_FD_ISSET(i, ex))
count++;
}
if (!count)
return;
/* Remove old callbacks: */
if (scheme_cb_ids)
for (i = 0; i < num_cbs; i++)
notify_set_input_func((Notify_client)NULL, (Notify_func)NULL,
scheme_cb_ids[i]);
num_cbs = count;
scheme_cb_ids = new int[num_cbs];
/* Install callbacks */
p = 0;
for (i = 0; i < limit; i++) {
if (MZ_FD_ISSET(i, rd))
scheme_cb_ids[p++] = XtAppAddInput(wxAPP_CONTEXT, i,
(XtPointer *)XtInputReadMask,
(XtInputCallbackProc)MrEdWakeUp, NULL);
if (MZ_FD_ISSET(i, wr))
scheme_cb_ids[p++] = XtAppAddInput(wxAPP_CONTEXT, i,
(XtPointer *)XtInputWriteMask,
(XtInputCallbackProc)MrEdWakeUp, NULL);
if (MZ_FD_ISSET(i, ex))
scheme_cb_ids[p++] = XtAppAddInput(wxAPP_CONTEXT, i,
(XtPointer *)XtInputExceptMask,
(XtInputCallbackProc)MrEdWakeUp,
NULL);
}
}
if (!count)
return;
/* callback function when input/exception is detected: */
Bool MrEdWakeUp(XtPointer, int *, XtInputId *)
{
int i;
/* Remove old callbacks: */
if (scheme_cb_ids)
for (i = 0; i < num_cbs; i++)
notify_set_input_func((Notify_client)NULL, (Notify_func)NULL,
scheme_cb_ids[i]);
if (scheme_cb_ids) {
/* Remove all callbacks: */
for (i = 0; i < num_cbs; i++)
XtRemoveInput(scheme_cb_ids[i]);
num_cbs = count;
scheme_cb_ids = new int[num_cbs];
scheme_cb_ids = NULL;
/* Install callbacks */
p = 0;
for (i = 0; i < limit; i++) {
if (MZ_FD_ISSET(i, rd))
scheme_cb_ids[p++] = XtAppAddInput(wxAPP_CONTEXT, i,
(XtPointer *)XtInputReadMask,
(XtInputCallbackProc)MrEdWakeUp, NULL);
if (MZ_FD_ISSET(i, wr))
scheme_cb_ids[p++] = XtAppAddInput(wxAPP_CONTEXT, i,
(XtPointer *)XtInputWriteMask,
(XtInputCallbackProc)MrEdWakeUp, NULL);
if (MZ_FD_ISSET(i, ex))
scheme_cb_ids[p++] = XtAppAddInput(wxAPP_CONTEXT, i,
(XtPointer *)XtInputExceptMask,
(XtInputCallbackProc)MrEdWakeUp,
NULL);
/* ``wake up'' */
scheme_wake_up();
}
return FALSE;
}
}
/* callback function when input/exception is detected: */
Bool MrEdWakeUp(XtPointer, int *, XtInputId *)
{
int i;
if (scheme_cb_ids) {
/* Remove all callbacks: */
for (i = 0; i < num_cbs; i++)
XtRemoveInput(scheme_cb_ids[i]);
scheme_cb_ids = NULL;
/* ``wake up'' */
scheme_wake_up();
}
return FALSE;
}
EOS
]
@; ----------------------------------------------------------------------
@section[#:tag "sleeping"]{Sleeping by Embedded Scheme}
@ -353,30 +350,29 @@ The following function @cpp{mzsleep} is an appropriate
@cpp{scheme_sleep} function for most any Unix or Windows application.
(This is approximately the built-in sleep used by Scheme.)
@verbatim[#<<EOS
void mzsleep(float v, void *fds)
{
if (v) {
sleep(v);
} else {
int limit;
fd_set *rd, *wr, *ex;
# ifdef WIN32
limit = 0;
# else
limit = getdtablesize();
# endif
@verbatim{
void mzsleep(float v, void *fds)
{
if (v) {
sleep(v);
} else {
int limit;
fd_set *rd, *wr, *ex;
rd = (fd_set *)fds;
wr = (fd_set *)scheme_get_fdset(fds, 1);
ex = (fd_set *)scheme_get_fdset(fds, 2);
# ifdef WIN32
limit = 0;
# else
limit = getdtablesize();
# endif
select(limit, rd, wr, ex, NULL);
rd = (fd_set *)fds;
wr = (fd_set *)scheme_get_fdset(fds, 1);
ex = (fd_set *)scheme_get_fdset(fds, 2);
select(limit, rd, wr, ex, NULL);
}
}
}
EOS
]
@; ----------------------------------------------------------------------
@ -476,12 +472,11 @@ Returns @cpp{1} if a break from @scheme[break-thread] or @cpp{scheme_break_threa
The @cpp{Scheme_Ready_Fun} and @cpp{Scheme_Needs_Wakeup_Fun}
types are defined as follows:
@verbatim[#<<EOS
@verbatim{
typedef int (*Scheme_Ready_Fun)(Scheme_Object *data);
typedef void (*Scheme_Needs_Wakeup_Fun)(Scheme_Object *data,
typedef void (*Scheme_Needs_Wakeup_Fun)(Scheme_Object *data,
void *fds);
EOS
]
}
Blocks the current thread until @var{f} with @var{data} returns a true
value. The @var{f} function is called periodically---at least once
@ -564,7 +559,7 @@ for more information.}
@function[(void scheme_wake_up)]{
This function is called by the embedding program
This function is called by the embedding program
when there is input on an external file descriptor. See
@secref["sleeping"] for more information.}
@ -628,13 +623,12 @@ Under Unix, and Mac OS X, this function has no effect.}
The argument types are defined as follows:
@verbatim[#<<EOS
@verbatim{
typedef int (*Scheme_Ready_Fun)(Scheme_Object *data);
typedef void (*Scheme_Needs_Wakeup_Fun)(Scheme_Object *data,
typedef void (*Scheme_Needs_Wakeup_Fun)(Scheme_Object *data,
void *fds);
typedef int (*Scheme_Wait_Filter_Fun)(Scheme_Object *data);
EOS
]
}
Extends the set of waitable objects for @scheme[sync]
to those with the type tag @var{type}. If @var{filter} is
@ -655,12 +649,11 @@ Like @cpp{scheme_add_evt}, but for objects where waiting is based
on a semaphore. Instead of @var{ready} and @var{wakeup} functions,
the @var{getsema} function extracts a semaphore for a given object:
@verbatim[#<<EOS
@verbatim{
typedef
Scheme_Object *(*Scheme_Wait_Sema_Fun)(Scheme_Object *data,
Scheme_Object *(*Scheme_Wait_Sema_Fun)(Scheme_Object *data,
int *repost);
EOS
]
}
If a successful wait should leave the semaphore waited, then
@var{getsema} should set @var{*repost} to @cpp{0}. Otherwise, the

View File

@ -683,13 +683,12 @@ Installs a printer to be used for printing (or writing or displaying)
values that have the type tag @var{type}.
The type of @var{printer} is defined as follows:\cppIndex{scheme_Type_Printer}
%
@verbatim[#<<EOS
@verbatim{
typedef void (*Scheme_Type_Printer)(Scheme_Object *v, int dis,
Scheme_Print_Params *pp);
EOS
]
%
}
Such a printer must print a representation of the value using
@cppi{scheme_print_bytes} and @cppi{scheme_print_string}. The
first argument to the printer, @var{v}, is the value to be printed.
@ -733,7 +732,7 @@ is only applied to values that both have tag @var{type}.
The type of @var{equalp}, @var{hash1}, and @var{hash2} are defined as
follows:
@verbatim[#<<EOS
@verbatim{
typedef int (*Scheme_Equal_Proc)(Scheme_Object* obj1,
Scheme_Object* obj2,
void* cycle_data);
@ -742,8 +741,7 @@ follows:
void* cycle_data);
typedef long (*Scheme_Secondary_Hash_Proc)(Scheme_Object* obj,
void* cycle_data);
EOS
]
}
The two hash functions are use to generate primary and secondary keys
for double hashing in an @scheme[equal?]-based hash table. The result

View File

@ -69,12 +69,11 @@ DrScheme.}
@link[url:download-drscheme]{Download PLT Scheme}, install, and then
start @exec{mzscheme} with no command-line arguments:
@verbatim[#<<EOS
@verbatim{
$ mzscheme
Welcome to MzScheme
>
EOS
]
}
If you're using a plain terminal, if you have GNU Readline installed
on your system, and if you'd like Readline support in @exec{mzscheme},

View File

@ -35,11 +35,9 @@ called from Scheme as
or with an @elem["@"] expression as
@verbatim[
#<<EOS
@verbatim|{
@title[#:tag "how-to"]{How to Design @italic{Great} Programs}
EOS
]
}|
Although the procedures are mostly design to be used from @elem["@"]
mode, they are easier to document in Scheme mode (partly because we

View File

@ -36,7 +36,7 @@ Some functions @deftech{decode} a sequence of @scheme[_pre-flow] or
function accepts any number of @scheme[_pre-content] arguments, so
that in
@verbatim[" @bold{``apple''}"]
@verbatim|{ @bold{``apple''}}|
the @litchar{``apple''} argument is decoded to use fancy quotes, and
then it is bolded.

View File

@ -25,15 +25,14 @@ To document a collection or @|PLaneT| package:
@filepath{manual.scrbl}.}
@item{Start @filepath{manual.scrbl} like this:
@verbatim[#<<EOS
#lang scribble/doc
@(require scribble/manual)
@verbatim|{
#lang scribble/doc
@(require scribble/manual)
@title{My Library}
@title{My Library}
Welcome to my documentation: @scheme[(list 'testing 1 2 3)].
EOS
]
Welcome to my documentation: @scheme[(list 'testing 1 2 3)].
}|
The first line starts the file in ``text'' mode, and
introduces the @litchar["@"] syntax to use Scheme bindings.
@ -136,12 +135,11 @@ that precede text to typeset.
Thus,
@verbatim[#<<EOS
@verbatim|{
@title{My Library}
@scheme[(list 'testing 1 2 3)]
@section[#:tag "here"]{You Are Here}
EOS
]
}|
means
@ -191,7 +189,7 @@ preferred mechanism for linking to information outside of a single
document. Such links require no information about where and how a
binding is documented elsewhere:
@verbatim[#<<EOS
@verbatim|{
#lang scribble/doc
@(require scribble/manual
(for-label scheme))
@ -199,15 +197,14 @@ binding is documented elsewhere:
@title{My Library}
See also @scheme[list].
EOS
]
}|
The @scheme[scheme] form typesets a Scheme expression for inline text,
so it ignores the source formatting of the expression. The
@scheme[schemeblock] form, in contrast, typesets inset Scheme code,
and it preserves the expression's formatting from the document source.
@verbatim[#<<EOS
@verbatim|{
#lang scribble/doc
@(require scribble/manual
(for-label scheme))
@ -223,8 +220,7 @@ and it preserves the expression's formatting from the document source.
"I've tried so hard to explain!"))
(nobody-understands-me "glorble snop")
]
EOS
]
}|
@; ----------------------------------------
@ -238,7 +234,7 @@ hyperlink with text other than the section title.
The following example illustrates section hyperlinks:
@verbatim[#<<EOS
@verbatim|{
#lang scribble/doc
@(require scribble/manual
(for-label scheme))
@ -252,15 +248,14 @@ The following example illustrates section hyperlinks:
@section[#:tag "chickens"]{Philadelphia Chickens}
Dancing tonight!
@section{Reprise}
See @secref{chickens}.
EOS
]
}|
Since the page is so short, it the hyperlinks in the above example are
more effective if you change the @filepath{info.ss} file to add the
@ -278,7 +273,7 @@ prefix, which is based on the target document's main source file. The
following example links to a section in the PLT Scheme reference
manual:
@verbatim[#<<EOS
@verbatim|{
#lang scribble/doc
@(require scribble/manual
(for-label scheme))
@ -288,8 +283,7 @@ manual:
@title{My Library}
See also @italic{@secref[#:doc ref-src]{pairs}}.
EOS
]
}|
As mentioned in @secref{scheme-hyperlinks}, however, cross-document
references based on @scheme[(require (for-label ....))] and
@ -313,7 +307,7 @@ to import the binding information of @filepath{helper.ss}. Then add a
binding with the module path as seen by a reader. Finally, use
@scheme[defproc] to document the procedure:
@verbatim[#<<EOS
@verbatim|{
#lang scribble/doc
@(require scribble/manual
(for-label scheme
@ -329,8 +323,7 @@ binding with the module path as seen by a reader. Finally, use
Replaces each @scheme['cow] in @scheme[lst] with
@scheme['aardvark].}
EOS
]
}|
In @scheme[defproc], a contract is specified with each argument to the
procedure. In this example, the contract for the @scheme[_lst]
@ -386,13 +379,13 @@ bindings introduced into the document source by
from the previous section, then @filepath{helper.ss} must be imported both
via @scheme[require-for-label] and @scheme[require]:
@verbatim[#<<EOS
@verbatim|{
#lang scribble/doc
@(require scribble/manual
scribble/eval ; <--- added
"helper.ss" ; <--- added
(for-label scheme
"helper.ss"))]
"helper.ss"))
@title{My Library}
@ -409,8 +402,7 @@ via @scheme[require-for-label] and @scheme[require]:
(my-helper '())
(my-helper '(cows such remarkable cows))
]}
EOS
]
}|
@;----------------------------------------
@section{Splitting the Document Source}
@ -423,7 +415,7 @@ as a sub-part of the enclosing part.
In @filepath{manual.scrbl}:
@verbatim[#<<EOS
@verbatim|{
#lang scribble/doc
@(require scribble/manual)
@ -434,24 +426,22 @@ In @filepath{manual.scrbl}:
@include-section["cows.scrbl"]
@include-section["aardvarks.scrbl"]
EOS
]
}|
In @filepath{cows.scrbl}:
@verbatim[#<<EOS
@verbatim|{
#lang scribble/doc
@(require scribble/manual)
@title{Cows}
Wherever they go, it's a quite a show.
EOS
]
}|
In @filepath{aardvarks.scrbl}:
@verbatim[#<<EOS
@verbatim|{
#lang scribble/doc
@(require scribble/manual
(for-label scheme
@ -464,8 +454,7 @@ In @filepath{aardvarks.scrbl}:
Replaces each @scheme['cow] in @scheme[lst] with
@scheme['aardvark].}
EOS
]
}|
@;----------------------------------------
@section{Multi-Page Sections}
@ -482,7 +471,7 @@ sub-sections.
Revising @filepath{cows.scrbl} from the previous section:
@verbatim[#<<EOS
@verbatim|{
#lang scribble/doc
@(require scribble/manual)
@ -495,8 +484,7 @@ Revising @filepath{cows.scrbl} from the previous section:
@section{Dancing}
See @secref["singing"].
EOS
]
}|
To run this example, remember to change @filepath{info.ss} to add the
@scheme['multi-page] style. You may also want to add a call to

View File

@ -27,7 +27,7 @@ alone, but @litchar["@"] forms can escape to S-expression mode.
A module written as
@verbatim[#<<EOS
@verbatim|{
#lang scribble/doc
@(require scribble/manual)
@ -37,8 +37,7 @@ A module written as
@bold{That} is the question.
Whether 'tis nobler...
EOS
]
}|
reads as

View File

@ -201,11 +201,11 @@ following spaces (or tabs) are part of the comment (similar to
Tip: if you're editing in a Scheme-aware editor (like DrScheme or
Emacs), it is useful to comment out blocks like this:
@verbatim["
@verbatim|{
@;{
...
;}
"]
}|
so the editor does not treat the file as having unbalanced
parenthesis.

View File

@ -57,14 +57,14 @@ when using @scheme[scheme], especially outside of @scheme[defproc] or
@scheme[defform]. Prefix a meta-variable with @litchar{_}; for
example,
@verbatim[" @scheme[(rator-expr rand-expr ...)]"]
@verbatim|{ @scheme[(rator-expr rand-expr ...)]}|
would be the wrong way to refer to the grammar of a function call,
because it produces @scheme[(rator-expr rand-expr ...)], where
@schemeidfont{rator-expr} and @schemeidfont{rand-expr} are
typeset as variables. The correct description is
@verbatim[" @scheme[(_rator-expr _rand-expr ...)]"]
@verbatim|{ @scheme[(_rator-expr _rand-expr ...)]}|
which produces @scheme[(_rator-expr _rand-expr ...)], where
@schemeidfont{rator-expr} @schemeidfont{rand-expr} are typeset as

View File

@ -34,7 +34,7 @@ offset of an embedded pict in a larger pict.
In addition to its drawing part, a pict has the following
@deftech{bounding box} structure:
@verbatim[#<<EOS
@verbatim{
w
------------------
| | a \
@ -42,9 +42,8 @@ In addition to its drawing part, a pict has the following
| | | h
|----------last----| |
| | d /
------------------
EOS
]
------------------
}
That is, the bounding box has a width @math{w} and a height
@math{h}. For a single text line, @math{d} is descent below the