A sync a day keeps... actually, it doesn't keep anyone away, and tends to make

one run into other people's bugs sooner, but OH WELL.

svn: r12543
This commit is contained in:
Stevie Strickland 2008-11-20 19:36:17 +00:00
commit 75c57820da
58 changed files with 1255 additions and 672 deletions

View File

@ -28,12 +28,12 @@
(hash-set! table n (car b)))))
table))
(define (list-ref/protect l pos)
(define (list-ref/protect l pos who)
(list-ref l pos)
#;
(if (pos . < . (length l))
(list-ref l pos)
`(OUT-OF-BOUNDS ,pos ,l)))
`(OUT-OF-BOUNDS ,who ,pos ,(length l) ,l)))
;; ----------------------------------------
@ -44,7 +44,7 @@
(let-values ([(globs defns) (decompile-prefix prefix)])
`(begin
,@defns
,(decompile-form form globs '(#%globals))))]
,(decompile-form form globs '(#%globals) (make-hasheq))))]
[else (error 'decompile "unrecognized: ~e" top)]))
(define (decompile-prefix a-prefix)
@ -76,7 +76,7 @@
lift-ids)
(map (lambda (stx id)
`(define ,id ,(if stx
`(#%decode-syntax ,(stx-encoded stx))
`(#%decode-syntax ,stx #;(stx-encoded stx))
#f)))
stxs stx-ids)))]
[else (error 'decompile-prefix "huh?: ~e" a-prefix)]))
@ -90,18 +90,19 @@
(match mod-form
[(struct mod (name self-modidx prefix provides requires body syntax-body max-let-depth))
(let-values ([(globs defns) (decompile-prefix prefix)]
[(stack) (append '(#%modvars) stack)])
[(stack) (append '(#%modvars) stack)]
[(closed) (make-hasheq)])
`(module ,name ....
,@defns
,@(map (lambda (form)
(decompile-form form globs stack))
(decompile-form form globs stack closed))
syntax-body)
,@(map (lambda (form)
(decompile-form form globs stack))
(decompile-form form globs stack closed))
body)))]
[else (error 'decompile-module "huh?: ~e" mod-form)]))
(define (decompile-form form globs stack)
(define (decompile-form form globs stack closed)
(match form
[(? mod?)
(decompile-module form stack)]
@ -109,31 +110,31 @@
`(define-values ,(map (lambda (tl)
(match tl
[(struct toplevel (depth pos const? mutated?))
(list-ref/protect globs pos)]))
(list-ref/protect globs pos 'def-vals)]))
ids)
,(decompile-expr rhs globs stack))]
,(decompile-expr rhs globs stack closed))]
[(struct def-syntaxes (ids rhs prefix max-let-depth))
`(define-syntaxes ,ids
,(let-values ([(globs defns) (decompile-prefix prefix)])
`(let ()
,@defns
,(decompile-form rhs globs '(#%globals)))))]
,(decompile-form rhs globs '(#%globals) closed))))]
[(struct def-for-syntax (ids rhs prefix max-let-depth))
`(define-values-for-syntax ,ids
,(let-values ([(globs defns) (decompile-prefix prefix)])
`(let ()
,@defns
,(decompile-expr rhs globs '(#%globals)))))]
,(decompile-expr rhs globs '(#%globals) closed))))]
[(struct sequence (forms))
`(begin ,@(map (lambda (form)
(decompile-form form globs stack))
(decompile-form form globs stack closed))
forms))]
[(struct splice (forms))
`(begin ,@(map (lambda (form)
(decompile-form form globs stack))
(decompile-form form globs stack closed))
forms))]
[else
(decompile-expr form globs stack)]))
(decompile-expr form globs stack closed)]))
(define (extract-name name)
(if (symbol? name)
@ -168,22 +169,22 @@
(extract-ids! body ids)]
[else #f]))
(define (decompile-expr expr globs stack)
(define (decompile-expr expr globs stack closed)
(match expr
[(struct toplevel (depth pos const? mutated?))
(let ([id (list-ref/protect globs pos)])
(let ([id (list-ref/protect globs pos 'toplevel)])
(if const?
id
`(#%checked ,id)))]
[(struct topsyntax (depth pos midpt))
(list-ref/protect globs (+ midpt pos))]
(list-ref/protect globs (+ midpt pos) 'topsyntax)]
[(struct primitive (id))
(hash-ref primitive-table id)]
[(struct assign (id rhs undef-ok?))
`(set! ,(decompile-expr id globs stack)
,(decompile-expr rhs globs stack))]
`(set! ,(decompile-expr id globs stack closed)
,(decompile-expr rhs globs stack closed))]
[(struct localref (unbox? offset clear?))
(let ([id (list-ref/protect stack offset)])
(let ([id (list-ref/protect stack offset 'localref)])
(let ([e (if unbox?
`(#%unbox ,id)
id)])
@ -191,17 +192,17 @@
`(#%sfs-clear ,e)
e)))]
[(? lam?)
`(lambda . ,(decompile-lam expr globs stack))]
`(lambda . ,(decompile-lam expr globs stack closed))]
[(struct case-lam (name lams))
`(case-lambda
,@(map (lambda (lam)
(decompile-lam lam globs stack))
(decompile-lam lam globs stack closed))
lams))]
[(struct let-one (rhs body))
(let ([id (or (extract-id rhs)
(gensym 'local))])
`(let ([,id ,(decompile-expr rhs globs (cons id stack))])
,(decompile-expr body globs (cons id stack))))]
`(let ([,id ,(decompile-expr rhs globs (cons id stack) closed)])
,(decompile-expr body globs (cons id stack) closed)))]
[(struct let-void (count boxes? body))
(let ([ids (make-vector count #f)])
(extract-ids! body ids)
@ -210,71 +211,76 @@
(or id (gensym 'localv)))])
`(let ,(map (lambda (i) `[,i ,(if boxes? `(#%box ?) '?)])
vars)
,(decompile-expr body globs (append vars stack)))))]
,(decompile-expr body globs (append vars stack) closed))))]
[(struct let-rec (procs body))
`(begin
(#%set!-rec-values ,(for/list ([p (in-list procs)]
[i (in-naturals)])
(list-ref/protect stack i))
(list-ref/protect stack i 'let-rec))
,@(map (lambda (proc)
(decompile-expr proc globs stack))
(decompile-expr proc globs stack closed))
procs))
,(decompile-expr body globs stack))]
,(decompile-expr body globs stack closed))]
[(struct install-value (count pos boxes? rhs body))
`(begin
(,(if boxes? '#%set-boxes! 'set!-values)
,(for/list ([i (in-range count)])
(list-ref/protect stack (+ i pos)))
,(decompile-expr rhs globs stack))
,(decompile-expr body globs stack))]
(list-ref/protect stack (+ i pos) 'install-value))
,(decompile-expr rhs globs stack closed))
,(decompile-expr body globs stack closed))]
[(struct boxenv (pos body))
(let ([id (list-ref/protect stack pos)])
(let ([id (list-ref/protect stack pos 'boxenv)])
`(begin
(set! ,id (#%box ,id))
,(decompile-expr body globs stack)))]
,(decompile-expr body globs stack closed)))]
[(struct branch (test then else))
`(if ,(decompile-expr test globs stack)
,(decompile-expr then globs stack)
,(decompile-expr else globs stack))]
`(if ,(decompile-expr test globs stack closed)
,(decompile-expr then globs stack closed)
,(decompile-expr else globs stack closed))]
[(struct application (rator rands))
(let ([stack (append (for/list ([i (in-list rands)]) (gensym 'rand))
stack)])
(annotate-inline
`(,(decompile-expr rator globs stack)
`(,(decompile-expr rator globs stack closed)
,@(map (lambda (rand)
(decompile-expr rand globs stack))
(decompile-expr rand globs stack closed))
rands))))]
[(struct apply-values (proc args-expr))
`(#%apply-values ,(decompile-expr proc globs stack)
,(decompile-expr args-expr globs stack))]
`(#%apply-values ,(decompile-expr proc globs stack closed)
,(decompile-expr args-expr globs stack closed))]
[(struct sequence (exprs))
`(begin ,@(for/list ([expr (in-list exprs)])
(decompile-expr expr globs stack)))]
(decompile-expr expr globs stack closed)))]
[(struct beg0 (exprs))
`(begin0 ,@(for/list ([expr (in-list exprs)])
(decompile-expr expr globs stack)))]
(decompile-expr expr globs stack closed)))]
[(struct with-cont-mark (key val body))
`(with-continuation-mark
,(decompile-expr key globs stack)
,(decompile-expr val globs stack)
,(decompile-expr body globs stack))]
,(decompile-expr key globs stack closed)
,(decompile-expr val globs stack closed)
,(decompile-expr body globs stack closed))]
[(struct closure (lam gen-id))
`(#%closed ,gen-id ,(decompile-expr lam globs stack))]
(if (hash-ref closed gen-id #f)
gen-id
(begin
(hash-set! closed gen-id #t)
`(#%closed ,gen-id ,(decompile-expr lam globs stack closed))))]
[(struct indirect (val))
(if (closure? val)
(closure-gen-id val)
(decompile-expr val globs stack closed)
'???)]
[else `(quote ,expr)]))
(define (decompile-lam expr globs stack)
(define (decompile-lam expr globs stack closed)
(match expr
[(struct closure (lam gen-id)) (decompile-lam lam globs stack)]
[(struct indirect (val)) (decompile-lam val globs stack closed)]
[(struct closure (lam gen-id)) (decompile-lam lam globs stack closed)]
[(struct lam (name flags num-params rest? closure-map max-let-depth body))
(let ([vars (for/list ([i (in-range num-params)])
(gensym (format "arg~a-" i)))]
[rest-vars (if rest? (list (gensym 'rest)) null)]
[captures (map (lambda (v)
(list-ref/protect stack v))
(list-ref/protect stack v 'lam))
(vector->list closure-map))])
`((,@vars . ,(if rest?
(car rest-vars)
@ -285,8 +291,10 @@
,@(if (null? captures)
null
`('(captures: ,@captures)))
,(decompile-expr body globs (append captures
(append vars rest-vars)))))]))
,(decompile-expr body globs
(append captures
(append vars rest-vars))
closed)))]))
(define (annotate-inline a)
(if (and (symbol? (car a))
@ -301,16 +309,16 @@
car cdr caar cadr cdar cddr
mcar mcdr unbox vector-length syntax-e
add1 sub1 - abs bitwise-not
list vector box))]
list list* vector vector-immutable box))]
[(3) (memq (car a) '(eq? = <= < >= >
bitwise-bit-set? char=?
+ - * / min max bitwise-and bitwise-ior
arithmetic-shift vector-ref string-ref bytes-ref
set-mcar! set-mcdr! cons mcons
list vector))]
list list* vector vector-immutable))]
[(4) (memq (car a) '(vector-set! string-set! bytes-set!
list vector))]
[else (memq (car a) '(list vector))]))
list list* vector vector-immutable))]
[else (memq (car a) '(list list* vector vector-immutable))]))
(cons '#%in a)
a))

View File

@ -661,7 +661,7 @@
;; Main parsing loop
(define (read-compact cp)
(let loop ([need-car 0] [proper #f] [last #f] [first #f])
(let loop ([need-car 0] [proper #f])
(begin-with-definitions
(define ch (cp-getc cp))
(define-values (cpt-start cpt-tag) (let ([x (cpt-table-lookup ch)])
@ -707,7 +707,7 @@
(cons (read-compact cp)
(if ppr null (read-compact cp)))
(read-compact-list l ppr cp))
(loop l ppr last first)))]
(loop l ppr)))]
[(let-one)
(make-let-one (read-compact cp) (read-compact cp))]
[(branch)
@ -747,8 +747,10 @@
(read-compact cp))])
(vector->immutable-vector (list->vector lst)))]
[(list) (let* ([n (read-compact-number cp)])
(for/list ([i (in-range n)])
(read-compact cp)))]
(append
(for/list ([i (in-range n)])
(read-compact cp))
(read-compact cp)))]
[(prefab)
(let ([v (read-compact cp)])
(apply make-prefab-struct
@ -845,9 +847,8 @@
[(symbol? s) s]
[(vector? s) (vector-ref s 0)]
[else 'closure]))))])
(vector-set! (cport-symtab cp) l cl)
(set-indirect-v! ind cl)
cl))]
ind))]
[(svector)
(read-compact-svector cp (read-compact-number cp))]
[(small-svector)
@ -858,7 +859,7 @@
[(and proper (= need-car 1))
(cons v null)]
[else
(cons v (loop (sub1 need-car) proper last first))]))))
(cons v (loop (sub1 need-car) proper))]))))
;; path -> bytes
;; implementes read.c:read_compiled
@ -898,11 +899,13 @@
(define symtab (make-vector symtabsize (make-not-ready)))
(define cp (make-cport 0 port size* rst symtab so* (make-vector symtabsize #f) (make-hash) (make-hash)))
(for/list ([i (in-range 1 symtabsize)])
(when (not-ready? (vector-ref symtab i))
(set-cport-pos! cp (vector-ref so* (sub1 i)))
(let ([v (read-compact cp)])
(vector-set! symtab i v))))
(set-cport-pos! cp shared-size)
(read-marshalled 'compilation-top-type cp)))

View File

@ -10,7 +10,7 @@
"private/run-status.ss"
"private/reloadable.ss"
"private/hooker.ss"
"web-status-server.ss"
(prefix-in web: "web-status-server.ss")
;; this sets some global parameter values, and this needs
;; to be done in the main thread, rather than later in a
;; user session thread (that will make the global changes
@ -622,9 +622,7 @@
(log-line "server started ------------------------------")
(hook 'server-start `([port ,(get-conf 'port-number)]))
(define stop-status
(cond [(get-conf 'https-port-number) => serve-status]
[else void]))
(define stop-status (web:run))
(define session-count 0)

View File

@ -74,7 +74,6 @@
[(allow-new-users) (values #f id )]
[(allow-change-info) (values #f id )]
[(master-password) (values #f id )]
[(web-base-dir) (values #f path/false )]
[(log-output) (values #t id )]
[(log-file) (values "log" path/false )]
[(web-log-file) (values #f path/false )]

View File

@ -50,9 +50,8 @@
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/}. Note the ``s'' in ``https''. Use the
``@tt{tester}'' username and ``@tt{pw}'' password, as before.
NOTE: The @scheme[https-port-number] line in the
@filepath{config.ss} file enables the embedded secure server. You

View File

@ -114,16 +114,6 @@ This directory contains the following files and sub-directories:
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 the handin collection for its
configuration; to have complete control over the built in server
content, you can copy and edit @filepath{status-web-root}, then
add this configuration entry set to the name of your new copy
(relative to the handin server directory, or absolute). Note that
you must copy the @filepath{servlets} directory if you want the
status servlet.}
@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
@ -218,11 +208,11 @@ This directory contains the following files and sub-directories:
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 fixed 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
startup time: port numbers and log file specs are fixed 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
@ -482,11 +472,11 @@ the correct assignment in the handin dialog.
A student can download his/her own submissions through a web server
that runs concurrently with the handin server. The starting URL is
@commandline{https://SERVER:PORT/servlets/status.ss}
@commandline{https://SERVER:PORT/}
to obtain a list of all assignments, or
@commandline{https://SERVER:PORT/servlets/status.ss?handin=ASSIGNMENT}
@commandline{https://SERVER:PORT/?handin=ASSIGNMENT}
to start with a specific assignment (named ASSIGNMENT). The default
PORT is 7980.

View File

@ -1,8 +0,0 @@
<html>
<head><title>Handin Status Web Server</title></head>
<body>
The handin status server is running.
<br>
You can <a href="/status.ss">check your submissions</a> on this server.
</body>
</html>

View File

@ -1,277 +0,0 @@
(module status mzscheme
(require mzlib/file
mzlib/list
mzlib/string
mzlib/date
web-server/servlet
web-server/servlet/servlet-structs
web-server/managers/timeouts
web-server/private/util
net/uri-codec
net/url
handin-server/private/md5
handin-server/private/logger
handin-server/private/config
handin-server/private/hooker)
(define get-user-data
(let ([users-file (build-path server-dir "users.ss")])
(lambda (user)
(get-preference (string->symbol user) (lambda () #f) #f users-file))))
(define (clean-str s)
(regexp-replace #rx" +$" (regexp-replace #rx"^ +" s "") ""))
(define (aget alist key)
(cond [(assq key alist) => cdr] [else #f]))
(define (make-page title . body)
`(html (head (title ,title))
(body ([bgcolor "white"]) (h1 ((align "center")) ,title) ,@body)))
(define (relativize-path p)
(path->string (find-relative-path (normalize-path server-dir) p)))
(define (make-k k tag)
(format "~a~atag=~a" k (if (regexp-match? #rx"^[^#]*[?]" k) "&" "?")
(uri-encode tag)))
;; `look-for' can be a username as a string (will find "bar+foo" for "foo"),
;; or a regexp that should match the whole directory name (used with
;; "^solution" below)
(define (find-handin-entry hi look-for)
(let ([dir (assignment<->dir hi)])
(and (directory-exists? dir)
(ormap
(lambda (d)
(let ([d (path->string d)])
(and (cond [(string? look-for)
(member look-for (regexp-split #rx" *[+] *" d))]
[(regexp? look-for) (regexp-match? look-for d)]
[else (error 'find-handin-entry
"internal error: ~e" look-for)])
(build-path dir d))))
(directory-list dir)))))
(define (handin-link k user hi)
(let* ([dir (find-handin-entry hi user)]
[l (and dir (with-handlers ([exn:fail? (lambda (x) null)])
(parameterize ([current-directory dir])
(sort (filter (lambda (f)
(and (not (equal? f "grade"))
(file-exists? f)))
(map path->string (directory-list)))
string<?))))])
(if (pair? l)
(cdr (apply append
(map (lambda (f)
(let ([hi (build-path dir f)])
`((br)
(a ([href ,(make-k k (relativize-path hi))]) ,f)
" ("
,(date->string
(seconds->date
(file-or-directory-modify-seconds hi))
#t)
")")))
l)))
(list (format "No handins accepted so far for user ~s, assignment ~s"
user hi)))))
(define (solution-link k hi)
(let ([soln (and (member (assignment<->dir hi) (get-conf 'inactive-dirs))
(find-handin-entry hi #rx"^solution"))]
[none `((i "---"))])
(cond [(not soln) none]
[(file-exists? soln)
`((a ((href ,(make-k k (relativize-path soln)))) "Solution"))]
[(directory-exists? soln)
(parameterize ([current-directory soln])
(let ([files (sort (map path->string
(filter file-exists? (directory-list)))
string<?)])
(if (null? files)
none
(apply append
(map (lambda (f)
`((a ([href ,(make-k k (relativize-path
(build-path soln f)))])
(tt ,f))
(br)))
files)))))]
[else none])))
(define (handin-grade user hi)
(let* ([dir (find-handin-entry hi user)]
[grade (and dir
(let ([filename (build-path dir "grade")])
(and (file-exists? filename)
(with-input-from-file filename
(lambda ()
(read-string (file-size filename)))))))])
(or grade "--")))
(define (one-status-page user for-handin)
(let* ([next (send/suspend
(lambda (k)
(make-page (format "User: ~a, Handin: ~a" user for-handin)
`(p ,@(handin-link k user for-handin))
`(p "Grade: " ,(handin-grade user for-handin))
`(p ,@(solution-link k for-handin))
`(p (a ([href ,(make-k k "allofthem")])
,(format "All handins for ~a" user))))))]
[tag (aget (request-bindings next) 'tag)])
(if (string=? tag "allofthem")
(all-status-page user)
(download user tag))))
(define (all-status-page user)
(define (cell . texts) `(td ([bgcolor "white"]) ,@texts))
(define (rcell . texts) `(td ([bgcolor "white"] [align "right"]) ,@texts))
(define (header . texts) `(td ([bgcolor "#f0f0f0"]) (big (strong ,@texts))))
(define ((row k active?) dir)
(let ([hi (assignment<->dir dir)])
`(tr ([valign "top"])
,(apply header hi
(if active? `((br) (small (small "[active]"))) '()))
,(apply cell (handin-link k user hi))
,(rcell (handin-grade user hi))
,(apply cell (solution-link k hi)))))
(let* ([next
(send/suspend
(lambda (k)
(make-page
(format "All Handins for ~a" user)
`(table ([bgcolor "#ddddff"] [cellpadding "6"] [align "center"])
(tr () ,@(map header '(nbsp "Files" "Grade" "Solution")))
,@(append (map (row k #t) (get-conf 'active-dirs))
(map (row k #f) (get-conf 'inactive-dirs)))))))]
[tag (aget (request-bindings next) 'tag)])
(download user tag)))
(define (download who tag)
(define (check path elts allow-active?)
(let loop ([path path] [elts (reverse elts)])
(let*-values ([(base name dir?) (split-path path)]
[(name) (path->string name)]
[(check) (and (pair? elts) (car elts))])
(if (null? elts)
;; must be rooted in a submission directory (why build-path instead
;; of using `path'? -- because path will have a trailing slash)
(member (build-path base name)
(get-conf (if allow-active? 'all-dirs 'inactive-dirs)))
(and (cond [(eq? '* check) #t]
[(regexp? check) (regexp-match? check name)]
[(string? check)
(or (equal? name check)
(member check (regexp-split #rx" *[+] *" name)))]
[else #f])
(loop base (cdr elts)))))))
(define file (build-path server-dir tag))
(with-handlers ([exn:fail?
(lambda (exn)
(log-line "Status exception: ~a" (exn-message exn))
(make-page "Error" "Illegal file access"))])
;; Make sure the user is allowed to read the requested file:
(or (check file `(,who *) #t)
(check file `(#rx"^solution") #f)
(check file `(#rx"^solution" *) #f)
(error 'download "bad file access for ~s: ~a" who file))
(log-line "Status file-get: ~s ~a" who file)
(hook 'status-file-get `([username ,(string->symbol who)] [file ,file]))
;; Return the downloaded file
(let* ([data (with-input-from-file file
(lambda () (read-bytes (file-size file))))]
[html? (regexp-match? #rx"[.]html?$" (string-foldcase tag))]
[wxme? (regexp-match? #rx#"^(?:#reader[(]lib\"read.ss\"\"wxme\"[)])?WXME" data)])
(make-response/full 200 "Okay" (current-seconds)
(cond [html? #"text/html"]
[wxme? #"application/data"]
[else #"text/plain"])
(list
(make-header #"Content-Length"
(string->bytes/latin-1
(number->string (bytes-length data))))
(make-header #"Content-Disposition"
(string->bytes/utf-8
(format "~a; filename=~s"
(if wxme? "attachment" "inline")
(let-values ([(base name dir?) (split-path file)])
(path->string name))))))
(list data)))))
(define (status-page user for-handin)
(log-line "Status access: ~s" user)
(hook 'status-login `([username ,(string->symbol user)]))
(if for-handin
(one-status-page user for-handin)
(all-status-page user)))
(define (login-page for-handin errmsg)
(let* ([request
(send/suspend
(lambda (k)
(make-page
"Handin Status Login"
`(form ([action ,k] [method "post"])
(table ([align "center"])
(tr (td ([colspan "2"] [align "center"])
(font ([color "red"]) ,(or errmsg 'nbsp))))
(tr (td "Username")
(td (input ([type "text"] [name "user"] [size "20"]
[value ""]))))
(tr (td nbsp))
(tr (td "Password")
(td (input ([type "password"] [name "passwd"]
[size "20"] [value ""]))))
(tr (td ([colspan "2"] [align "center"])
(input ([type "submit"] [name "post"]
[value "Login"])))))))))]
[bindings (request-bindings request)]
[user (aget bindings 'user)]
[passwd (aget bindings 'passwd)]
[user (and user (clean-str user))]
[user-data (get-user-data user)])
(cond [(and user-data
(string? passwd)
(let ([pw (md5 passwd)])
(or (equal? pw (car user-data))
(equal? pw (get-conf 'master-password)))))
(status-page user for-handin)]
[else (login-page for-handin "Bad username or password")])))
(define web-counter
(let ([sema (make-semaphore 1)]
[count 0])
(lambda ()
(dynamic-wind
(lambda () (semaphore-wait sema))
(lambda () (set! count (add1 count)) (format "w~a" count))
(lambda () (semaphore-post sema))))))
(define (start initial-request)
(parameterize ([current-session (web-counter)])
(login-page (aget (request-bindings initial-request) 'handin) #f)))
(define interface-version 'v2)
(define name "status")
(define (instance-expiration-handler failed-request)
(let* (;; get the current url, and strip off the continuation data
[cont-url (request-uri failed-request)]
[base-url (url-replace-path
(lambda (pl)
(map (lambda (pp)
(make-path/param (path/param-path pp) empty))
pl))
cont-url)]
[base-url-str (url->string base-url)])
`(html (head (meta [(http-equiv "refresh")
(content ,(format "3;URL=~a" base-url-str))]))
(body "Your session has expired, "
(a ([href ,base-url-str]) "restarting") " in 3 seconds."))))
(define manager
(create-timeout-manager instance-expiration-handler 600 600))
(provide interface-version start name manager))

View File

@ -1,82 +1,283 @@
#lang scheme/base
(require scheme/unit
net/ssl-tcp-unit
net/tcp-sig
net/tcp-unit
(only-in mzlib/etc this-expression-source-directory)
web-server/web-server-unit
web-server/web-server-sig
web-server/web-config-sig
web-server/web-config-unit
web-server/configuration/namespace
"private/config.ss")
#lang scheme
(require scheme/list
scheme/file
scheme/date
net/uri-codec
web-server/servlet
web-server/servlet-env
web-server/managers/lru
handin-server/private/md5
handin-server/private/logger
handin-server/private/config
handin-server/private/hooker)
(provide serve-status)
(define (aget alist key)
(cond [(assq key alist) => cdr] [else #f]))
(define (serve-status port-no)
(define (clean-str s)
(regexp-replace #rx" +$" (regexp-replace #rx"^ +" s "") ""))
(define ((in-dir dir) . paths) (path->string (apply build-path dir paths)))
(define in-web-dir
(in-dir (or (get-conf 'web-base-dir)
(build-path (this-expression-source-directory)
"status-web-root"))))
(define in-plt-web-dir
(in-dir (build-path (collection-path "web-server") "default-web-root")))
(define (make-page title . body)
`(html (head (title ,title))
(body ([bgcolor "white"]) (h1 ((align "center")) ,title) ,@body)))
(define config
`((port ,port-no)
(max-waiting 40)
(initial-connection-timeout 30)
(default-host-table
(host-table
(default-indices "index.html")
(log-format parenthesized-default)
(messages
(servlet-message "servlet-error.html")
(authentication-message "forbidden.html")
(servlets-refreshed "servlet-refresh.html")
(passwords-refreshed "passwords-refresh.html")
(file-not-found-message "not-found.html")
(protocol-message "protocol-error.html")
(collect-garbage "collect-garbage.html"))
(timeouts
(default-servlet-timeout 120)
(password-connection-timeout 300)
(servlet-connection-timeout 86400)
(file-per-byte-connection-timeout 1/20)
(file-base-connection-timeout 30))
(paths
(configuration-root ,(in-plt-web-dir "conf"))
(host-root ".")
(log-file-path ,(cond [(get-conf 'web-log-file) => path->string]
[else #f]))
(file-root ".")
(servlet-root ,(in-web-dir "servlets"))
(mime-types ,(in-plt-web-dir "mime.types"))
(password-authentication ,(in-plt-web-dir "passwords")))))
(virtual-host-table)))
(define get-user-data
(let ([users-file (build-path server-dir "users.ss")])
(unless (file-exists? users-file)
(error 'get-user-data "users file missing at: ~a" users-file))
(lambda (user)
(get-preference (string->symbol user) (lambda () #f) #f users-file))))
(define configuration
(configuration-table-sexpr->web-config@
config
#:web-server-root (in-web-dir)
#:make-servlet-namespace
(make-make-servlet-namespace
#:to-be-copied-module-specs
'(handin-server/private/md5
handin-server/private/logger
handin-server/private/config
handin-server/private/hooker
handin-server/private/reloadable))))
(define (relativize-path p)
(path->string (find-relative-path (normalize-path server-dir) p)))
(define-unit-binding config@ configuration (import) (export web-config^))
(define-unit-binding ssl-tcp@
(make-ssl-tcp@ "server-cert.pem" "private-key.pem" #f #f #f #f #f)
(import) (export tcp^))
(define-compound-unit/infer status-server@
(import)
(link ssl-tcp@ config@ web-server@)
(export web-server^))
(define-values/invoke-unit/infer status-server@)
(define (make-k k tag)
(format "~a~atag=~a" k (if (regexp-match? #rx"^[^#]*[?]" k) "&" "?")
(uri-encode tag)))
(serve))
;; `look-for' can be a username as a string (will find "bar+foo" for "foo"), or
;; a regexp that should match the whole directory name (used with "^solution"
;; below)
(define (find-handin-entry hi look-for)
(let ([dir (assignment<->dir hi)])
(and (directory-exists? dir)
(ormap
(lambda (d)
(let ([d (path->string d)])
(and (cond [(string? look-for)
(member look-for (regexp-split #rx" *[+] *" d))]
[(regexp? look-for) (regexp-match? look-for d)]
[else (error 'find-handin-entry
"internal error: ~e" look-for)])
(build-path dir d))))
(directory-list dir)))))
(define (handin-link k user hi)
(let* ([dir (find-handin-entry hi user)]
[l (and dir (with-handlers ([exn:fail? (lambda (x) null)])
(parameterize ([current-directory dir])
(sort (filter (lambda (f)
(and (not (equal? f "grade"))
(file-exists? f)))
(map path->string (directory-list)))
string<?))))])
(if (pair? l)
(cdr (append-map
(lambda (f)
(let ([hi (build-path dir f)])
`((br)
(a ([href ,(make-k k (relativize-path hi))]) ,f)
" ("
,(date->string
(seconds->date (file-or-directory-modify-seconds hi))
#t)
")")))
l))
(list (format "No handins accepted so far for user ~s, assignment ~s"
user hi)))))
(define (solution-link k hi)
(let ([soln (and (member (assignment<->dir hi) (get-conf 'inactive-dirs))
(find-handin-entry hi #rx"^solution"))]
[none `((i "---"))])
(cond [(not soln) none]
[(file-exists? soln)
`((a ((href ,(make-k k (relativize-path soln)))) "Solution"))]
[(directory-exists? soln)
(parameterize ([current-directory soln])
(let ([files (sort (map path->string
(filter file-exists? (directory-list)))
string<?)])
(if (null? files)
none
(apply append
(map (lambda (f)
`((a ([href ,(make-k k (relativize-path
(build-path soln f)))])
(tt ,f))
(br)))
files)))))]
[else none])))
(define (handin-grade user hi)
(let* ([dir (find-handin-entry hi user)]
[grade (and dir
(let ([filename (build-path dir "grade")])
(and (file-exists? filename)
(with-input-from-file filename
(lambda ()
(read-string (file-size filename)))))))])
(or grade "--")))
(define (one-status-page user for-handin)
(let* ([next (send/suspend
(lambda (k)
(make-page (format "User: ~a, Handin: ~a" user for-handin)
`(p ,@(handin-link k user for-handin))
`(p "Grade: " ,(handin-grade user for-handin))
`(p ,@(solution-link k for-handin))
`(p (a ([href ,(make-k k "allofthem")])
,(format "All handins for ~a" user))))))]
[tag (aget (request-bindings next) 'tag)])
(if (string=? tag "allofthem")
(all-status-page user)
(download user tag))))
(define (all-status-page user)
(define (cell . texts) `(td ([bgcolor "white"]) ,@texts))
(define (rcell . texts) `(td ([bgcolor "white"] [align "right"]) ,@texts))
(define (header . texts) `(td ([bgcolor "#f0f0f0"]) (big (strong ,@texts))))
(define ((row k active?) dir)
(let ([hi (assignment<->dir dir)])
`(tr ([valign "top"])
,(apply header hi (if active? `((br) (small (small "[active]"))) '()))
,(apply cell (handin-link k user hi))
,(rcell (handin-grade user hi))
,(apply cell (solution-link k hi)))))
(let* ([next
(send/suspend
(lambda (k)
(make-page
(format "All Handins for ~a" user)
`(table ([bgcolor "#ddddff"] [cellpadding "6"] [align "center"])
(tr () ,@(map header '(nbsp "Files" "Grade" "Solution")))
,@(append (map (row k #t) (get-conf 'active-dirs))
(map (row k #f) (get-conf 'inactive-dirs)))))))]
[tag (aget (request-bindings next) 'tag)])
(download user tag)))
(define (download who tag)
(define (check path elts allow-active?)
(let loop ([path path] [elts (reverse elts)])
(let*-values ([(base name dir?) (split-path path)]
[(name) (path->string name)]
[(check) (and (pair? elts) (car elts))])
(if (null? elts)
;; must be rooted in a submission directory (why build-path instead
;; of using `path'? -- because path will have a trailing slash)
(member (build-path base name)
(get-conf (if allow-active? 'all-dirs 'inactive-dirs)))
(and (cond [(eq? '* check) #t]
[(regexp? check) (regexp-match? check name)]
[(string? check)
(or (equal? name check)
(member check (regexp-split #rx" *[+] *" name)))]
[else #f])
(loop base (cdr elts)))))))
(define file (build-path server-dir tag))
(with-handlers ([exn:fail?
(lambda (exn)
(log-line "Status exception: ~a" (exn-message exn))
(make-page "Error" "Illegal file access"))])
;; Make sure the user is allowed to read the requested file:
(or (check file `(,who *) #t)
(check file `(#rx"^solution") #f)
(check file `(#rx"^solution" *) #f)
(error 'download "bad file access for ~s: ~a" who file))
(log-line "Status file-get: ~s ~a" who file)
(hook 'status-file-get `([username ,(string->symbol who)] [file ,file]))
;; Return the downloaded file
(let* ([data (file->bytes file)]
[html? (regexp-match? #rx"[.]html?$" (string-foldcase tag))]
[wxme? (regexp-match?
#rx#"^(?:#reader[(]lib\"read.ss\"\"wxme\"[)])?WXME" data)])
(make-response/full 200 "Okay" (current-seconds)
(cond [html? #"text/html"]
[wxme? #"application/data"]
[else #"text/plain"])
(list
(make-header #"Content-Length"
(string->bytes/latin-1
(number->string (bytes-length data))))
(make-header #"Content-Disposition"
(string->bytes/utf-8
(format "~a; filename=~s"
(if wxme? "attachment" "inline")
(let-values ([(base name dir?) (split-path file)])
(path->string name))))))
(list data)))))
(define (status-page user for-handin)
(log-line "Status access: ~s" user)
(hook 'status-login `([username ,(string->symbol user)]))
(if for-handin
(one-status-page user for-handin)
(all-status-page user)))
(define (login-page for-handin errmsg)
(let* ([request
(send/suspend
(lambda (k)
(make-page
"Handin Status Login"
`(form ([action ,k] [method "post"])
(table ([align "center"])
(tr (td ([colspan "2"] [align "center"])
(font ([color "red"]) ,(or errmsg 'nbsp))))
(tr (td "Username")
(td (input ([type "text"] [name "user"] [size "20"]
[value ""]))))
(tr (td nbsp))
(tr (td "Password")
(td (input ([type "password"] [name "passwd"]
[size "20"] [value ""]))))
(tr (td ([colspan "2"] [align "center"])
(input ([type "submit"] [name "post"]
[value "Login"])))))))))]
[bindings (request-bindings request)]
[user (aget bindings 'user)]
[passwd (aget bindings 'passwd)]
[user (and user (clean-str user))]
[user-data (get-user-data user)])
(cond [(and user-data
(string? passwd)
(let ([pw (md5 passwd)])
(or (equal? pw (car user-data))
(equal? pw (get-conf 'master-password)))))
(status-page user for-handin)]
[else (login-page for-handin "Bad username or password")])))
(define web-counter
(let ([sema (make-semaphore 1)] [count 0])
(lambda ()
(dynamic-wind
(lambda () (semaphore-wait sema))
(lambda () (set! count (add1 count)) (format "w~a" count))
(lambda () (semaphore-post sema))))))
(define ((send-error msg) req)
`(html (head (meta [(http-equiv "refresh") (content "3;URL=/")])
(title ,msg))
(body ,msg "; " (a ([href "/"]) "restarting") " in 3 seconds.")))
(define ((run-servlet port))
(define dir (string->path server-dir))
(serve/servlet
(lambda (request)
(parameterize ([current-session (web-counter)])
(login-page (aget (request-bindings request) 'handin) #f)))
#:port port #:listen-ip #f #:ssl? #t #:command-line? #t
#:servlet-path "/" #:servlet-regexp #rx""
#:server-root-path dir #:servlets-root dir
#:file-not-found-responder (send-error "File not found")
#:servlet-namespace '(handin-server/private/md5
handin-server/private/logger
handin-server/private/config
handin-server/private/hooker
handin-server/private/reloadable)
#:manager (make-threshold-LRU-manager
(send-error "Your session has expired") (* 12 1024 1024))
#:log-file (get-conf 'web-log-file)))
(provide run)
(define (run)
(cond [(get-conf 'https-port-number)
=> (lambda (p)
(define t
(thread (lambda ()
(dynamic-wind
(lambda () (log-line "*** starting web server"))
(run-servlet p)
(lambda () (log-line "*** web server died!"))))))
(lambda () (break-thread t)))]
[else void]))

View File

@ -44,7 +44,7 @@ re-exported by @schememodname[net/url].}
[query (listof (cons/c symbol? (or/c false/c string?)))]
[fragment (or/c false/c string?)])]{
The basic structure for all URLs, hich is explained in RFC 3986
The basic structure for all URLs, which is explained in RFC 3986
@cite["RFC3986"]. The following diagram illustrates the parts:
@verbatim[#:indent 2]|{

View File

@ -1 +1 @@
#lang scheme/base (provide stamp) (define stamp "19nov2008")
#lang scheme/base (provide stamp) (define stamp "20nov2008")

View File

@ -350,6 +350,9 @@
(un0 '(1) 'list 1)
(bin0 '(1 2) 'list 1 2)
(tri0 '(1 2 3) 'list (lambda () 1) 2 3 void)
(un0 '1 'list* 1)
(bin0 '(1 . 2) 'list* 1 2)
(tri0 '(1 2 . 3) 'list* (lambda () 1) 2 3 void)
(un0 '#&1 'box 1)
(let ([test-setter
@ -443,17 +446,19 @@
(list a b c d e f))])
10))
(test-comp (normalize-depth '(let* ([i (cons 0 1)][j i]) j))
(normalize-depth '(let* ([i (cons 0 1)]) i)))
;; We use nonsense `display' and `write' where we used to use `cons' and
;; `list', because the old ones now get optimized away:
(test-comp (normalize-depth '(let* ([i (display 0 1)][j i]) j))
(normalize-depth '(let* ([i (display 0 1)]) i)))
(test-comp (normalize-depth '(let* ([i (cons 0 1)][j (list 2)][k (list 3)][g i]) g))
(normalize-depth '(let* ([i (cons 0 1)][j (list 2)][k (list 3)]) i)))
(test-comp (normalize-depth '(let* ([i (display 0 1)][j (write 2)][k (write 3)][g i]) g))
(normalize-depth '(let* ([i (display 0 1)][j (write 2)][k (write 3)]) i)))
(test-comp (normalize-depth '(let* ([i (cons 0 1)][j (list 2)][k (list 3)][g i][h g]) h))
(normalize-depth '(let* ([i (cons 0 1)][j (list 2)][k (list 3)]) i)))
(test-comp (normalize-depth '(let* ([i (display 0 1)][j (write 2)][k (write 3)][g i][h g]) h))
(normalize-depth '(let* ([i (display 0 1)][j (write 2)][k (write 3)]) i)))
(test-comp (normalize-depth '(let* ([i (cons 0 1)][g i][h (car g)][m h]) m))
(normalize-depth '(let* ([i (cons 0 1)][h (car i)]) h)))
(test-comp (normalize-depth '(let* ([i (display 0 1)][g i][h (car g)][m h]) m))
(normalize-depth '(let* ([i (display 0 1)][h (car i)]) h)))
; (require #%kernel) ;
@ -685,6 +690,26 @@
(define (q x)
(+ 1 (+ 1 (+ 1 (+ 1 (+ 1 (+ 1 (+ 1 (+ 1 (+ 1 (+ 1 (+ x 10))))))))))))))
(let ([test-dropped
(lambda (cons-name . args)
(test-comp `(let ([x 5])
(let ([y (,cons-name ,@args)])
x))
5))])
(test-dropped 'cons 1 2)
(test-dropped 'mcons 1 2)
(test-dropped 'box 1)
(let ([test-multi
(lambda (cons-name)
(test-dropped cons-name 1 2)
(test-dropped cons-name 1 2 3)
(test-dropped cons-name 1)
(test-dropped cons-name))])
(test-multi 'list)
(test-multi 'list*)
(test-multi 'vector)
(test-multi 'vector-immutable)))
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Check bytecode verification of lifted functions

View File

@ -286,9 +286,9 @@
w
h))))
(define (filled-rounded-rectangle w h [corner-radius 0.25] #:angle [angle 0])
(define (filled-rounded-rectangle w h [corner-radius -0.25] #:angle [angle 0])
(let ([dc-path (new dc-path%)])
(send dc-path rounded-rectangle 0 0 w h (- corner-radius))
(send dc-path rounded-rectangle 0 0 w h corner-radius)
(send dc-path rotate angle)
(let-values ([(x y w h) (send dc-path get-bounding-box)])
(dc (λ (dc dx dy)

View File

@ -2,6 +2,7 @@
(require
scheme/list
scheme/tcp
(only-in rnrs/lists-6 fold-left)
'#%paramz
(only-in '#%kernel [apply kernel:apply])
@ -480,4 +481,16 @@
[eof (-val eof)]
[read-accept-reader (-Param B B)]
[maybe-print-message (-String . -> . -Void)]
[maybe-print-message (-String . -> . -Void)]
;; scheme/tcp
[tcp-listener? (make-pred-ty -TCP-Listener)]
[tcp-abandon-port (-Port . -> . -Void)]
[tcp-accept (-TCP-Listener . -> . (-values (list -Input-Port -Output-Port)) )]
[tcp-accept/enable-break (-TCP-Listener . -> . (-values (list -Input-Port -Output-Port)) )]
[tcp-accept-ready? (-TCP-Listener . -> . B )]
[tcp-addresses (-Port . -> . (-values (list N N)))]
[tcp-close (-TCP-Listener . -> . -Void )]
[tcp-connect (-String -Integer . -> . (-values (list -Input-Port -Output-Port)))]
[tcp-connect/enable-break (-String -Integer . -> . (-values (list -Input-Port -Output-Port)))]
[tcp-listen (N . -> . -TCP-Listener)]

View File

@ -12,7 +12,7 @@
scheme/promise
(for-syntax macro-debugger/stxclass/stxclass)
(for-syntax scheme/base)
(for-template scheme/base scheme/contract))
(for-template scheme/base scheme/contract scheme/tcp))
(provide (all-defined-out)
;; these should all eventually go away
@ -134,6 +134,7 @@
(define -Namespace (make-Base 'Namespace #'namespace?))
(define -Output-Port (make-Base 'Output-Port #'output-port?))
(define -Input-Port (make-Base 'Input-Port #'input-port?))
(define -TCP-Listener (make-Base 'TCP-Listener #'tcp-listener?))
(define -Syntax make-Syntax)
(define -HT make-Hashtable)

View File

@ -0,0 +1,16 @@
#lang typed-scheme
(require typed/private/utils)
(require/opaque-type GIF-Stream gif-stream? file/gif)
(require/typed/provide file/gif
[gif-start ( Output-Port Number Number Number (U #f (Listof (Vectorof Number))) -> Void )]
[gif-add-image ( GIF-Stream Number Number Number Number Boolean (U #f Number) String -> Void )]
[gif-add-control ( GIF-Stream Symbol Boolean Number (U #f Number) -> Void)]
[gif-add-loop-control ( GIF-Stream Number -> Void )]
[gif-add-comment ( GIF-Stream String -> Void )]
[gif-end ( GIF-Stream -> Void )]
[quantize ( String -> (values String (Listof (Vectorof Number)) (U #f (Vectorof Number))))])
(provide gif-stream? GIF-Stream)

View File

@ -1,6 +1,7 @@
#lang typed-scheme
(require (only-in typed/mred/mred dt require/typed/provide Font%))
(require typed/private/utils
(only-in typed/mred/mred Font%))
(dt Style-List% (Class ()
()

View File

@ -1,14 +1,6 @@
#lang typed-scheme
(define-syntax-rule (dt nm t)
(begin (define-type-alias nm t) (provide nm)))
(define-syntax-rule (require/typed/provide lib [nm t] ...)
(begin
(require/typed lib [nm t] ...)
(provide nm ...)))
(provide dt require/typed/provide)
(require typed/private/utils)
(dt Bitmap% (Class (Number Number Boolean)
()

View File

@ -0,0 +1,13 @@
#lang typed-scheme
(require typed/private/utils)
(require/typed/provide net/base64
[base64-encode-stream (case-lambda (Input-Port Output-Port -> Void)
(Input-Port Output-Port Bytes -> Void))]
[base64-decode-stream (Input-Port Output-Port -> Void)]
[base64-encode (Bytes -> Bytes)]
[base64-decode (Bytes -> Bytes)])
(provide base64-encode-stream base64-decode-stream base64-encode base64-decode)

27
collects/typed/net/cgi.ss Normal file
View File

@ -0,0 +1,27 @@
#lang typed-scheme
(require typed/private/utils)
(require-typed-struct cgi-error () net/cgi)
(require-typed-struct incomplete-%-suffix ([chars : (Listof Char)]) net/cgi)
(require-typed-struct invalid-%-suffix ([char : Char]) net/cgi)
(require/typed/provide net/cgi
[get-bindings (-> (Listof (cons (U Symbol String) String)))]
[get-bindings/post (-> (Listof (Pair (U Symbol String) String)))]
[get-bindings/get (-> (Listof (Pair (U Symbol String) String)) )]
[output-http-headers (-> Void)]
[generate-html-output (case-lambda (String (Listof String) -> Void)
(String (Listof String) String String String String String -> Void))]
[generate-error-output ((Listof String) -> (U))]
[bindings-as-html ((Listof (cons (U Symbol String) String)) -> (Listof String))]
[extract-bindings ((U Symbol String) (Listof (cons (U Symbol String) String)) -> ( Listof String))]
[extract-binding/single ((U Symbol String) (Listof (Pair (U Symbol String) String)) -> String)]
[get-cgi-method (-> (U "GET" "POST"))]
[string->html (String -> String)]
[generate-link-text (String String -> String)])
(provide
(struct-out cgi-error)
(struct-out incomplete-%-suffix)
(struct-out invalid-%-suffix))

View File

@ -0,0 +1,23 @@
#lang typed-scheme
(require typed/private/utils)
(require/opaque-type Cookie cookie? net/cookie)
(require/typed/provide net/cookie
[set-cookie (String String -> Cookie)]
[cookie:add-comment (Cookie String -> Cookie)]
[cookie:add-domain (Cookie String -> Cookie)]
[cookie:add-max-age (Cookie Number -> Cookie)]
[cookie:add-path (Cookie String -> Cookie)]
[cookie:secure (Cookie Boolean -> Cookie)]
[cookie:version (Cookie Number -> Cookie)]
[print-cookie (Cookie -> String)]
[get-cookie (String String -> (Listof String))]
[get-cookie/single (String String -> (Option String))])
(require-typed-struct cookie-error () net/cookie)
(provide Cookie cookie? (struct-out cookie-error))

10
collects/typed/net/dns.ss Normal file
View File

@ -0,0 +1,10 @@
#lang typed-scheme
(require typed/private/utils)
(require/typed/provide net/dns
[dns-get-address (String String -> String)]
[dns-get-name (String String -> String)]
[dns-get-mail-exchanger (String String -> String )]
[dns-find-nameserver (-> (Option String))])

16
collects/typed/net/ftp.ss Normal file
View File

@ -0,0 +1,16 @@
#lang typed-scheme
(require typed/private/utils)
(require/opaque-type FTP-Connection ftp-connection? net/ftp)
(require/typed/provide net/ftp
[ftp-cd (FTP-Connection String -> Void)]
[ftp-establish-connection (String Number String String -> FTP-Connection)]
[ftp-close-connection (FTP-Connection -> Void)]
[ftp-directory-list (FTP-Connection -> (Listof (List (U "-" "d" "l") String String)))]
[ftp-download-file (FTP-Connection Path String -> Void)]
[ftp-make-file-seconds (String -> Number)])
(provide ftp-connection? FTP-Connection)

View File

@ -0,0 +1,4 @@
#lang typed-scheme
(require typed/file/gif)
(provide (all-from-out typed/file/gif))

View File

@ -0,0 +1,31 @@
#lang typed-scheme
(require typed/private/utils)
(require/typed/provide net/head
[empty-header String]
[validate-header (String -> Void)]
[extract-field (Bytes (U Bytes String) -> (Option Bytes))]
[remove-field (String String -> String)]
[insert-field (String String String -> String)]
[replace-field (String String String -> String)]
[extract-all-fields ((U String Bytes) -> (Listof (cons (U String Bytes) (U Bytes String))))]
[append-headers (String String -> String)]
[standard-message-header (String (Listof String) (Listof String) (Listof String) String -> String)]
[data-lines->data ((Listof String) -> String)]
[extract-addresses (String Symbol -> (U (Listof String) (Listof (Listof String))))]
[assemble-address-field ((Listof String) -> String)])
(provide
empty-header
validate-header
extract-field
remove-field
insert-field
replace-field
extract-all-fields
append-headers
standard-message-header
data-lines->data
extract-addresses
assemble-address-field)

View File

@ -0,0 +1,55 @@
#lang typed-scheme
(require typed/private/utils)
(require/opaque-type IMAP-Connection imap-connection? net/imap)
(define-type-alias bstring (U String Bytes))
(require/typed/provide net/imap
[imap-port-number (Number -> Void)]
[imap-connect (String String String String -> (values IMAP-Connection Number Number))]
[imap-connect* (Number Number String String String -> (values IMAP-Connection Number Number))]
[imap-disconnect (IMAP-Connection -> Void)]
[imap-force-disconnect (IMAP-Connection -> Void)]
[imap-reselect (IMAP-Connection String -> (values Number Number))]
[imap-examine (IMAP-Connection String -> (values Number Number))]
[imap-noop (IMAP-Connection -> (values Number Number))]
[imap-status (IMAP-Connection String (Listof Symbol) -> (Listof (Listof Number)))]
[imap-poll (IMAP-Connection -> Void)]
[imap-new? (IMAP-Connection -> Boolean)]
[imap-messages (IMAP-Connection -> Number)]
[imap-recent (IMAP-Connection -> Number)]
[imap-uidnext (IMAP-Connection -> (Option Number))]
[imap-uidvalidity (IMAP-Connection -> (Option Number))]
[imap-unseen (IMAP-Connection -> (Option Number))]
[imap-reset-new! (IMAP-Connection -> Void)]
[imap-get-expunges (IMAP-Connection -> (Listof Number))]
[imap-pending-expunges? (IMAP-Connection -> Boolean)]
[imap-get-updates (IMAP-Connection -> (Listof (cons Number (Listof (Pair Any Any)))))]
[imap-pending-updates? (IMAP-Connection -> Boolean)]
[imap-get-messages
(IMAP-Connection (Listof Number) Symbol -> (Listof (Listof (U Number String String (Listof Symbol)))))]
[imap-copy (IMAP-Connection (Listof Number) String -> Void)]
[imap-append (IMAP-Connection String String -> Void)]
[imap-store (IMAP-Connection Symbol (Listof Number) Symbol -> Void)]
[imap-flag->symbol (Symbol -> Symbol)]
[symbol->imap-flag (Symbol -> Symbol)]
[imap-expunge (IMAP-Connection -> Void)]
[imap-mailbox-exists? (IMAP-Connection String -> Boolean)]
[imap-create-mailbox (IMAP-Connection String -> Void)]
[imap-list-child-mailboxes
(case-lambda (IMAP-Connection bstring -> (Listof (cons (Listof Symbol) (cons String '()))))
(IMAP-Connection bstring (Option bstring) -> (Listof (List (Listof Symbol) String))))]
[imap-mailbox-flags (IMAP-Connection String -> (Listof Symbol))]
[imap-get-hierarchy-delimiter (IMAP-Connection -> String)])
(provide
imap-connection?
IMAP-Connection)

View File

@ -0,0 +1,71 @@
#lang typed-scheme
(require typed/private/utils)
;; -- basic mime structures --
(require-typed-struct disposition
([type : Symbol]
[filename : String]
[creation : String]
[modification : String]
[read : String]
[size : Number]
[params : Any])
net/mime)
(require-typed-struct entity ([type : (U Symbol String)]
[subtype : (U Symbol String)]
[charset : (U Symbol String)]
[encoding : Symbol]
[disposition : disposition ]
[params : (Listof (cons Symbol String))]
[id : String]
[description : String]
[other : String]
[fields : Any]
[parts : (Listof String) ]
[body : (Output-Port -> Void)])
net/mime)
(require-typed-struct message
([version : String] [entity : entity] [fields : (Listof Symbol)])
net/mime)
;; -- exceptions raised --
(require/typed mime-error? (Any -> Boolean : (Opaque mime-error?)) net/mime)
(require/typed unexpected-termination? (Any -> Boolean :(Opaque unexpected-termination?)) net/mime)
(require/typed unexpected-termination-msg ((Opaque unexpected-termination?) -> message) net/mime)
(require/typed missing-multipart-boundary-parameter? (Any -> Boolean : (Opaque missing-multipart-boundary-parameter?)) net/mime)
(require/typed malformed-multipart-entity? (Any -> Boolean : (Opaque malformed-multipart-entity?)) net/mime)
(require/typed malformed-multipart-entity-msg ((Opaque malformed-multipart-entity?)-> message) net/mime)
(require/typed empty-mechanism? (Any -> Boolean : (Opaque empty-mechanism?)) net/mime)
(require/typed empty-type? (Any -> Boolean : (Opaque empty-type?)) net/mime)
(require/typed empty-subtype? (Any -> Boolean : (Opaque empty-subtype?)) net/mime)
(require/typed empty-disposition-type? (Any -> Boolean : (Opaque empty-disposition-type?)) net/mime)
;; -- mime methods --
(require/typed/provide net/mime
[mime-analyze ((U Bytes Input-Port) Any -> message)])
(provide
;; -- exceptions raised --
mime-error?
unexpected-termination?
unexpected-termination-msg
missing-multipart-boundary-parameter?
malformed-multipart-entity?
malformed-multipart-entity-msg
empty-mechanism?
empty-type?
empty-subtype?
empty-disposition-type?
;; -- basic mime structures --
message
entity
disposition
;; -- mime methods --
mime-analyze
)

View File

@ -0,0 +1,31 @@
#lang typed-scheme
(require typed/private/utils)
(require-typed-struct communicator ([sender : Number] [receiver : Number] [server : String] [port : Number])
net/nntp)
(require/typed/provide net/nntp
[connect-to-server (case-lambda (String -> communicator) (String Number -> communicator))]
[disconnect-from-server (communicator -> Void)]
[authenticate-user (communicator String String -> Void)]
[open-news-group (communicator String -> (values Number Number Number))]
[head-of-message (communicator Number -> (Listof String))]
[body-of-message (communicator Number -> (Listof String))]
[newnews-since (communicator Number -> (Listof String))]
[generic-message-command (communicator Number -> (Listof String))]
[make-desired-header (String -> String)] ;;-> Regexp
[extract-desired-headers ((Listof String) (Listof String) -> (Listof String))]) ;;2nd: Of Regexp
#|
;; requires structure inheritance
(require-typed-struct nntp ()]
(require-typed-struct unexpected-response ([code : Number] [text : String])]
(require-typed-struct bad-status-line ([line : String])]
(require-typed-struct premature-close ([communicator : communicator])]
(require-typed-struct bad-newsgroup-line ([line : String])]
(require-typed-struct non-existent-group ([group : String])]
(require-typed-struct article-not-in-group ([article : Number])]
(require-typed-struct no-group-selected ()]
(require-typed-struct article-not-found ([article : Number])]
(require-typed-struct authentication-rejected ()]
|#

View File

@ -0,0 +1,38 @@
#lang typed-scheme
(require typed/private/utils)
(require-typed-struct communicator ([sender : Number] [receiver : Number] [server : String] [port : Number] [state : Symbol])net/pop3)
(require/typed/provide net/pop3
[connect-to-server ( case-lambda (String -> (Opaque communicator?)) (String Number -> (Opaque communicator?)) )]
[disconnect-from-server ( (Opaque communicator?) -> Void )]
[authenticate/plain-text ( String String (Opaque communicator?) -> Void )]
[get-mailbox-status ( (Opaque communicator?) -> (values Number Number) )]
[get-message/complete ( (Opaque communicator?) Number -> (values (Listof String)(Listof String)) )]
[get-message/headers ( (Opaque communicator?) Number -> (Listof String) )]
[get-message/body ( (Opaque communicator?) Number -> (Listof String) )]
[delete-message ( (Opaque communicator?) Number -> Void )]
[get-unique-id/single ( (Opaque communicator?) Number -> String )]
[get-unique-id/all ( (Opaque communicator?) -> (Listof (cons Number String)) )]
[make-desired-header ( String -> String )];-> Regexp
[extract-desired-headers ( (Listof String)(Listof String)-> (Listof String) )];2nd:of Regexp
)
(provide (struct-out communicator))
#|
(require-typed-struct pop3 ()]
(require-typed-struct cannot-connect ()]
(require-typed-struct username-rejected ()]
(require-typed-struct password-rejected ()]
(require-typed-struct not-ready-for-transaction ([ communicator : (Opaque communicator?) ])net/pop3)
(require-typed-struct not-given-headers ([ communicator : (Opaque communicator?) ] [message : String])]
(require-typed-struct illegal-message-number ([communicator : (Opaque communicator?)] [message : String])]
(require-typed-struct cannot-delete-message ([communicator : (Opaque communicator?)] [message : String])]
(require-typed-struct disconnect-not-quiet ([communicator : (Opaque communicator?)])]
(require-typed-struct malformed-server-response ([communicator : (Opaque communicator?)])net/pop3)
|#

10
collects/typed/net/qp.ss Normal file
View File

@ -0,0 +1,10 @@
#lang typed-scheme
(require typed/private/utils)
(require/typed/provide net/qp
[qp-encode ( String -> String )]
[qp-decode ( String -> String )]
[qp-encode-stream (case-lambda (Input-Port Output-Port -> Void) (Input-Port Output-Port String -> Void) )]
[qp-decode-stream ( Input-Port Output-Port -> Void )])

View File

@ -0,0 +1,12 @@
#lang typed-scheme
(require typed/private/utils)
(require/typed/provide net/sendmail
[send-mail-message/port
(String String (Listof String) (Listof String) (Listof String) String * -> Output-Port)]
[send-mail-message
(String String (Listof String) (Listof String) (Listof String) (Listof String) String * -> Output-Port)])
(provide send-mail-message/port send-mail-message #;no-mail-recipients)

View File

@ -0,0 +1,9 @@
#lang typed-scheme
(require/typed net/sendurl
[send-url (String -> Void)]
[unix-browser-list (Listof Symbol)]
[browser-preference? (String -> Boolean)]
[external-browser (-> (U Symbol #f (Pair String String)))])
(provide send-url unix-browser-list browser-preference? external-browser)

View File

@ -0,0 +1,11 @@
#lang typed-scheme
(require typed/private/utils)
(require/typed/provide net/smtp
[smtp-send-message (String String (Listof String) String (Listof String) -> Void)]
[smtp-sending-end-of-message (Parameter (-> Any))])
(provide smtp-send-message smtp-sending-end-of-message)

View File

@ -0,0 +1,15 @@
#lang typed-scheme
(require typed/private/utils)
(require/typed/provide net/uri-codec
[uri-encode ( String -> String )]
[uri-decode ( String -> String )]
[form-urlencoded-encode ( String -> String )]
[form-urlencoded-decode ( String -> String )]
[alist->form-urlencoded ( (Listof (cons Symbol String)) -> String )]
[form-urlencoded->alist ( String -> (Listof (cons Symbol String)) )]
[current-alist-separator-mode (Parameter Symbol)])

59
collects/typed/net/url.ss Normal file
View File

@ -0,0 +1,59 @@
#lang typed-scheme
(require typed/private/utils)
(require-typed-struct path/param ([path : (U String 'up 'same)] [param : (Listof String)]) net/url)
(require-typed-struct url ([scheme : (Option String)]
[user : (Option String)]
[host : (Option String)]
[port : (Option Integer)]
[path-absolute? : Boolean]
[path : (Listof path/param)]
[query : (Listof (Pair Symbol (Option String)))]
[fragment : (Option String)])
net/url)
(require/opaque-type URL-Exception url-exception? net/url)
(define-type-alias PortT (case-lambda (url -> Input-Port) (url (Listof String)-> Input-Port)))
(define-type-alias PortT/String (case-lambda (url String -> Input-Port) (url String (Listof String)-> Input-Port)))
(require/typed/provide net/url
[path->url (Path -> url)]
[url->path (case-lambda (url -> Path) (url (U 'unix 'windows) -> Path))]
[file-url-path-convention-type (Parameter (U 'unix 'windows))]
[get-pure-port PortT]
[head-pure-port PortT]
[delete-pure-port PortT]
[get-impure-port PortT]
[head-impure-port PortT]
[delete-impure-port PortT]
[post-pure-port PortT/String]
[put-pure-port PortT/String]
[post-impure-port PortT/String]
[put-impure-port PortT/String]
[display-pure-port (Input-Port -> Void)]
[purify-port (Input-Port -> String)]
[call/input-url (case-lambda [url url (Input-Port -> Any) -> Any])] ;;FIXME - need polymorphism
[current-proxy-servers (Parameter (Listof (List String String Integer)))]
[netscape/string->url (String -> url)]
[string->url (String -> url)]
[url->string (url -> String)]
[combine-url/relative (url String -> url)])
(provide
URL-Exception
url-exception?
(struct-out url)
(struct-out path/param))

View File

@ -0,0 +1,11 @@
#lang typed-scheme
(define-syntax-rule (dt nm t)
(begin (define-type-alias nm t) (provide nm)))
(define-syntax-rule (require/typed/provide lib [nm t] ...)
(begin
(require/typed lib [nm t] ...)
(provide nm ...)))
(provide dt require/typed/provide)

View File

@ -51,10 +51,6 @@
#:responders-servlet (url? any/c . -> . response?))
dispatcher/c)])
;; default-server-instance-expiration-handler : (request -> response)
(define (default-servlet-instance-expiration-handler req)
(next-dispatcher))
(define (make url->servlet
#:responders-servlet-loading [responders-servlet-loading servlet-loading-responder]
#:responders-servlet [responders-servlet servlet-error-responder])
@ -70,15 +66,6 @@
(define response
(with-handlers ([exn:fail:filesystem:exists?
(lambda (the-exn) (next-dispatcher))]
[exn:fail:servlet-manager:no-instance?
(lambda (the-exn)
((exn:fail:servlet-manager:no-instance-expiration-handler the-exn) req))]
[exn:fail:servlet-manager:no-continuation?
(lambda (the-exn)
((exn:fail:servlet-manager:no-continuation-expiration-handler the-exn) req))]
[exn:fail:servlet:instance?
(lambda (the-exn)
(default-servlet-instance-expiration-handler req))]
[(lambda (x) #t)
(lambda (the-exn) (responders-servlet-loading uri the-exn))])
(define the-servlet (url->servlet uri))
@ -87,10 +74,7 @@
[current-directory (servlet-directory the-servlet)]
[current-namespace (servlet-namespace the-servlet)])
(with-handlers ([(lambda (x) #t)
(lambda (exn)
(responders-servlet
(request-uri req)
exn))])
(lambda (exn) (responders-servlet uri exn))])
(call-with-continuation-barrier
(lambda ()
(call-with-continuation-prompt

View File

@ -18,7 +18,7 @@
default)))
(define ssl (make-parameter #f))
(define port (make-parameter 80))
(define port (make-parameter #f))
(define configuration@
(parse-command-line
@ -27,7 +27,7 @@
`((once-each
[("--ssl")
,(lambda (flag)
(port 443)
(unless (port) (port 443))
(ssl #t))
("Run with SSL using server-cert.pem and private-key.pem in the current directory, with 443 as the default port.")]
[("-f" "--configuration-table")
@ -41,7 +41,10 @@
("Use an alternate configuration table" "file-name")]
[("-p" "--port")
,(lambda (flag the-port)
(port (string->number the-port)))
(let ([p (string->number the-port)])
(if (and (integer? p) (<= 1 p 65535))
(port p)
(error 'web-server "expecting a valid port number, got \"~a\"" the-port))))
("Use an alternate network port." "port")]
[("-a" "--ip-address")
,(lambda (flag ip-address)
@ -58,7 +61,7 @@
(lambda (flags)
(configuration-table->web-config@
(extract-flag 'config flags default-configuration-table-path)
#:port (port)
#:port (or (port) 80)
#:listen-ip (extract-flag 'ip-address flags #f)))
'()))

View File

@ -1,7 +1,7 @@
#lang scheme/base
(require mzlib/contract
mzlib/plt-match
mzlib/string)
(require scheme/contract
scheme/match
scheme/promise)
(require "util.ss"
web-server/http)
(provide/contract
@ -17,13 +17,9 @@
(match (read-line (current-input-port) 'any)
[(? eof-object?)
(void)]
[(regexp #"^([^\t ]+)[\t ]+(.+)$"
(list s type exts))
(for-each (lambda (ext)
(hash-set! MIME-TYPE-TABLE
(lowercase-symbol! ext)
type))
(regexp-split #" " exts))
[(regexp #rx#"^([^\t ]+)[\t ]+(.+)$" (list _ type exts))
(for ([ext (in-list (regexp-split #" " exts))])
(hash-set! MIME-TYPE-TABLE (lowercase-symbol! ext) type))
(loop)]
[_
(loop)]))))
@ -36,12 +32,11 @@
;; 1. Can we determine the mime type based on file contents?
;; 2. Assuming that 7-bit ASCII is correct for mime-type
(define (make-path->mime-type a-path)
(define MIME-TYPE-TABLE (read-mime-types a-path))
(define file-suffix-regexp (byte-regexp #".*\\.([^\\.]*$)"))
(define MIME-TYPE-TABLE (delay (read-mime-types a-path)))
(lambda (path)
(match (regexp-match file-suffix-regexp (path->bytes path))
[(list path-bytes sffx)
(hash-ref MIME-TYPE-TABLE
(match (path->bytes path)
[(regexp #rx#".*\\.([^\\.]*$)" (list _ sffx))
(hash-ref (force MIME-TYPE-TABLE)
(lowercase-symbol! sffx)
(lambda () TEXT/HTML-MIME-TYPE))]
TEXT/HTML-MIME-TYPE)]
[_ TEXT/HTML-MIME-TYPE])))

View File

@ -4,7 +4,6 @@
web-server/http)
(define servlet-prompt (make-continuation-prompt-tag 'servlet))
(define-struct (exn:fail:servlet:instance exn:fail) ())
(define-struct servlet (custodian namespace manager directory handler)
#:mutable)
(define-struct execution-context (request))
@ -18,9 +17,6 @@
(provide/contract
[servlet-prompt continuation-prompt-tag?]
[struct (exn:fail:servlet:instance exn:fail)
([message string?]
[continuation-marks continuation-mark-set?])]
[struct servlet
([custodian custodian?]
[namespace namespace?]

View File

@ -6,7 +6,10 @@
@(require (for-label web-server/servlet-env
web-server/http
web-server/managers/lru
web-server/private/util
web-server/configuration/configuration-table
web-server/configuration/responders
web-server/dispatchers/dispatch-log
scheme/list))
@defmodule[web-server/servlet-env]{
@ -82,12 +85,16 @@ If you want to use @scheme[serve/servlet] in a start up script for a Web server,
[#:launch-browser? launch-browser? boolean? (not command-line?)]
[#:quit? quit? boolean? (not command-line?)]
[#:banner? banner? boolean? (not command-line?)]
[#:listen-ip listen-ip string? "127.0.0.1"]
[#:listen-ip listen-ip (or/c false/c string?) "127.0.0.1"]
[#:port port number? 8000]
[#:ssl? ssl? boolean? #f]
[#:servlet-path servlet-path string?
"/servlets/standalone.ss"]
[#:servlet-regexp servlet-regexp regexp?
(regexp (format "^~a$" (regexp-quote servlet-path)))]
(regexp
(format
"^~a$"
(regexp-quote servlet-path)))]
[#:stateless? stateless? boolean? #f]
[#:manager manager manager? (make-threshold-LRU-manager #f (* 1024 1024 64))]
[#:servlet-namespace servlet-namespace (listof module-path?) empty]
@ -96,9 +103,24 @@ If you want to use @scheme[serve/servlet] in a start up script for a Web server,
[#:servlets-root servlets-root path? (build-path server-root-path "htdocs")]
[#:servlet-current-directory servlet-current-directory path? servlets-root]
[#:file-not-found-responder file-not-found-responder
(gen-file-not-found-responder (build-path server-root-path "conf" "not-found.html"))]
(request? . -> . response?)
(gen-file-not-found-responder
(build-path
server-root-path
"conf"
"not-found.html"))]
[#:mime-types-path mime-types-path path?
(build-path server-root-path "mime.types")])
(let ([p (build-path
server-root-path
"mime.types")])
(if (file-exists? p)
p
(build-path
(directory-part
default-configuration-table-path)
"mime.types")))]
[#:log-file log-file path? #f]
[#:log-format log-format symbol? 'apache-default])
void]{
This sets up and starts a fairly default server instance.
@ -115,6 +137,9 @@ If you want to use @scheme[serve/servlet] in a start up script for a Web server,
The server listens on @scheme[listen-ip] and port @scheme[port].
If @scheme[ssl?] is true, then the server runs in HTTPS mode with @filepath{<server-root-path>/server-cert.pem}
and @filepath{<server-root-path>/private-key.pem} as the certificates and private keys
The servlet is loaded with @scheme[manager]
as its continuation manager. (The default manager limits the amount of memory to 64 MB and
deals with memory pressure as discussed in the @scheme[make-threshold-LRU-manager] documentation.)
@ -133,6 +158,9 @@ If you want to use @scheme[serve/servlet] in a start up script for a Web server,
running from the command line, in which case the @scheme[command-line?] option controls similar options.
MIME types are looked up at @scheme[mime-types-path].
If @scheme[log-file] is given, then it used to log requests using @scheme[log-format] as the format. Allowable formats
are those allowed by @scheme[log-format->format].
}
}

View File

@ -3,13 +3,17 @@
#lang scheme/base
(require (prefix-in net: net/sendurl)
scheme/contract
scheme/list)
scheme/list
scheme/unit
net/tcp-unit
net/tcp-sig
net/ssl-tcp-unit)
(require web-server/web-server
web-server/managers/lru
web-server/managers/manager
web-server/private/servlet
web-server/configuration/namespace
web-server/private/cache-table
web-server/private/cache-table
web-server/http
web-server/private/util
web-server/configuration/responders
@ -18,11 +22,12 @@
web-server/configuration/configuration-table
web-server/servlet/setup
(prefix-in lift: web-server/dispatchers/dispatch-lift)
(prefix-in fsmap: web-server/dispatchers/filesystem-map)
(prefix-in fsmap: web-server/dispatchers/filesystem-map)
(prefix-in sequencer: web-server/dispatchers/dispatch-sequencer)
(prefix-in files: web-server/dispatchers/dispatch-files)
(prefix-in filter: web-server/dispatchers/dispatch-filter)
(prefix-in servlets: web-server/dispatchers/dispatch-servlets))
(prefix-in filter: web-server/dispatchers/dispatch-filter)
(prefix-in servlets: web-server/dispatchers/dispatch-servlets)
(prefix-in log: web-server/dispatchers/dispatch-log))
(define send-url (make-parameter net:send-url))
@ -30,93 +35,117 @@
(lift:make
(lambda (request)
(thread (lambda () (sleep 2) (semaphore-post sema)))
`(html
(head
(title "Server Stopped")
(link ([rel "stylesheet"] [href "/error.css"])))
(body
(div ([class "section"])
(div ([class "title"]) "Server Stopped")
(p "Return to DrScheme.")))))))
`(html (head (title "Server Stopped")
(link ([rel "stylesheet"] [href "/error.css"])))
(body (div ([class "section"])
(div ([class "title"]) "Server Stopped")
(p "Return to DrScheme.")))))))
(provide/contract
[serve/servlet (((request? . -> . response?))
(#:command-line? boolean?
#:launch-browser? boolean?
#:quit? boolean?
#:banner? boolean?
#:listen-ip string?
#:port number?
#:manager manager?
#:servlet-namespace (listof module-path?)
#:server-root-path path?
#:stateless? boolean?
#:extra-files-paths (listof path?)
#:servlets-root path?
#:file-not-found-responder (request? . -> . response?)
#:mime-types-path path?
#:servlet-path string?
#:servlet-regexp regexp?)
#:launch-browser? boolean?
#:quit? boolean?
#:banner? boolean?
#:listen-ip (or/c false/c string?)
#:port number?
#:ssl? boolean?
#:manager manager?
#:servlet-namespace (listof module-path?)
#:server-root-path path?
#:stateless? boolean?
#:extra-files-paths (listof path?)
#:servlets-root path?
#:file-not-found-responder (request? . -> . response?)
#:mime-types-path path?
#:servlet-path string?
#:servlet-regexp regexp?
#:log-file (or/c false/c path?))
. ->* .
void)])
(define (serve/servlet start
#:command-line?
[command-line? #f]
#:launch-browser?
[launch-browser? (not command-line?)]
#:quit?
[quit? (not command-line?)]
#:banner?
[banner? (not command-line?)]
#:listen-ip
[listen-ip "127.0.0.1"]
#:port
[the-port 8000]
#:manager
[manager
(make-threshold-LRU-manager
(lambda (request)
`(html (head (title "Page Has Expired."))
(body (p "Sorry, this page has expired. Please go back."))))
(* 64 1024 1024))]
#:servlet-path
[servlet-path "/servlets/standalone.ss"]
#:servlet-regexp
[servlet-regexp (regexp (format "^~a$" (regexp-quote servlet-path)))]
#:stateless?
[stateless? #f]
#:servlet-namespace
[servlet-namespace empty]
#:server-root-path
[server-root-path (directory-part default-configuration-table-path)]
#:extra-files-paths
[extra-files-paths (list (build-path server-root-path "htdocs"))]
#:servlets-root
[servlets-root (build-path server-root-path "htdocs")]
#:servlet-current-directory
[servlet-current-directory servlets-root]
#:file-not-found-responder
[file-not-found-responder (gen-file-not-found-responder (build-path server-root-path "conf" "not-found.html"))]
#:mime-types-path
[mime-types-path (build-path server-root-path "mime.types")])
;; utility for conveniently chaining dispatchers
(define (dispatcher-sequence . dispatchers)
(let loop ([ds dispatchers] [r '()])
(cond [(null? ds) (apply sequencer:make (reverse r))]
[(not (car ds)) (loop (cdr ds) r)]
[(list? (car ds)) (loop (append (car ds) (cdr ds)) r)]
[else (loop (cdr ds) (cons (car ds) r))])))
(define (serve/servlet
start
#:command-line?
[command-line? #f]
#:launch-browser?
[launch-browser? (not command-line?)]
#:quit?
[quit? (not command-line?)]
#:banner?
[banner? (not command-line?)]
#:listen-ip
[listen-ip "127.0.0.1"]
#:port
[the-port 8000]
#:ssl?
[ssl? #f]
#:manager
[manager
(make-threshold-LRU-manager
(lambda (request)
`(html (head (title "Page Has Expired."))
(body (p "Sorry, this page has expired. Please go back."))))
(* 64 1024 1024))]
#:servlet-path
[servlet-path "/servlets/standalone.ss"]
#:servlet-regexp
[servlet-regexp (regexp (format "^~a$" (regexp-quote servlet-path)))]
#:stateless?
[stateless? #f]
#:servlet-namespace
[servlet-namespace empty]
#:server-root-path
[server-root-path (directory-part default-configuration-table-path)]
#:extra-files-paths
[extra-files-paths (list (build-path server-root-path "htdocs"))]
#:servlets-root
[servlets-root (build-path server-root-path "htdocs")]
#:servlet-current-directory
[servlet-current-directory servlets-root]
#:file-not-found-responder
[file-not-found-responder
(gen-file-not-found-responder
(build-path server-root-path "conf" "not-found.html"))]
#:mime-types-path
[mime-types-path (let ([p (build-path server-root-path "mime.types")])
(if (file-exists? p)
p
(build-path
(directory-part default-configuration-table-path)
"mime.types")))]
#:log-file
[log-file #f]
#:log-format
[log-format 'apache-default])
(define standalone-url
(format "http://localhost:~a~a" the-port servlet-path))
(string-append (if ssl? "https" "http")
"://localhost"
(if (and (not ssl?) (= the-port 80))
"" (format ":~a" the-port))
servlet-path))
(define make-servlet-namespace
(make-make-servlet-namespace
#:to-be-copied-module-specs servlet-namespace))
(make-make-servlet-namespace #:to-be-copied-module-specs servlet-namespace))
(define sema (make-semaphore 0))
(define servlet-box (box #f))
(define dispatcher
(sequencer:make
(if quit?
(filter:make
#rx"^/quit$"
(quit-server sema))
(lambda _ (next-dispatcher)))
(dispatcher-sequence
(and log-file (log:make #:format (log:log-format->format log-format)
#:log-path log-file))
(and quit? (filter:make #rx"^/quit$" (quit-server sema)))
(filter:make
servlet-regexp
(servlets:make
@ -129,8 +158,8 @@
#:additional-specs
default-module-specs)])
(if stateless?
(make-stateless.servlet servlet-current-directory start)
(make-v2.servlet servlet-current-directory manager start)))])
(make-stateless.servlet servlet-current-directory start)
(make-v2.servlet servlet-current-directory manager start)))])
(set-box! servlet-box servlet)
servlet)))))
(let-values ([(clear-cache! url->servlet)
@ -142,35 +171,40 @@
(make-default-path->servlet
#:make-servlet-namespace make-servlet-namespace))])
(servlets:make url->servlet))
(apply sequencer:make
(map (lambda (extra-files-path)
(files:make
#:url->path (fsmap:make-url->path
extra-files-path)
#:path->mime-type (make-path->mime-type mime-types-path)
#:indices (list "index.html" "index.htm")))
extra-files-paths))
(files:make
#:url->path (fsmap:make-url->path
(build-path server-root-path "htdocs"))
#:path->mime-type (make-path->mime-type (build-path server-root-path "mime.types"))
(map (lambda (extra-files-path)
(files:make
#:url->path (fsmap:make-url->path extra-files-path)
#:path->mime-type (make-path->mime-type mime-types-path)
#:indices (list "index.html" "index.htm")))
extra-files-paths)
(files:make
#:url->path (fsmap:make-url->path (build-path server-root-path "htdocs"))
#:path->mime-type (make-path->mime-type mime-types-path)
#:indices (list "index.html" "index.htm"))
(lift:make file-not-found-responder)))
(define shutdown-server
(serve #:dispatch dispatcher
#:listen-ip listen-ip
#:port the-port))
#:port the-port
#:tcp@ (if ssl?
(let ()
(define-unit-binding ssl-tcp@
(make-ssl-tcp@
(build-path server-root-path "server-cert.pem")
(build-path server-root-path "private-key.pem")
#f #f #f #f #f)
(import) (export tcp^))
ssl-tcp@)
tcp@)))
(when launch-browser?
((send-url) standalone-url #t))
(when banner?
(printf "Your Web application is running at ~a.~n" standalone-url)
(printf "Click 'Stop' at any time to terminate the Web Server.~n"))
(with-handlers
([exn:break?
(lambda (exn)
(when banner?
(printf "~nWeb Server stopped.~n"))
(shutdown-server))])
(semaphore-wait/enable-break sema))
; We shouldn't get here, because nothing posts to the semaphore. But just in case...
(shutdown-server))
(printf "Your Web application is running at ~a.\n" standalone-url)
(printf "Click 'Stop' at any time to terminate the Web Server.\n"))
(let ([bye (lambda ()
(when banner? (printf "\nWeb Server stopped.\n"))
(shutdown-server))])
(with-handlers ([exn:break? (lambda (exn) (bye))])
(semaphore-wait/enable-break sema)
;; We can get here if a /quit url is visited
(bye))))

View File

@ -49,19 +49,26 @@
(lambda (req)
(define uri (request-uri req))
(define-values (instance-id handler)
(cond
[(continuation-url? uri)
=> (match-lambda
[(list instance-id k-id salt)
(values instance-id
(custodian-box-value ((manager-continuation-lookup manager) instance-id k-id salt)))])]
[else
(values ((manager-create-instance manager) (exit-handler))
start)]))
(parameterize ([current-servlet-instance-id instance-id])
(handler req)))))
(with-handlers ([exn:fail:servlet-manager:no-instance?
(lambda (the-exn)
((exn:fail:servlet-manager:no-instance-expiration-handler the-exn) req))]
[exn:fail:servlet-manager:no-continuation?
(lambda (the-exn)
((exn:fail:servlet-manager:no-continuation-expiration-handler the-exn) req))])
(define-values (instance-id handler)
(cond
[(continuation-url? uri)
=> (match-lambda
[(list instance-id k-id salt)
(values instance-id
(custodian-box-value ((manager-continuation-lookup manager) instance-id k-id salt)))])]
[else
(values ((manager-create-instance manager) (exit-handler))
start)]))
(parameterize ([current-servlet-instance-id instance-id])
(handler req))))))
(define (make-stateless.servlet directory start)
(define ses

View File

@ -15,25 +15,25 @@
[serve
(->* (#:dispatch dispatcher/c)
(#:tcp@ unit?
#:port number?
#:listen-ip (or/c false/c string?)
#:max-waiting number?
#:initial-connection-timeout number?)
#:port number?
#:listen-ip (or/c false/c string?)
#:max-waiting number?
#:initial-connection-timeout number?)
(-> void))]
[serve/ports
(->* (#:dispatch dispatcher/c)
(#:tcp@ unit?
#:ports (listof number?)
#:listen-ip (or/c false/c string?)
#:max-waiting number?
#:initial-connection-timeout number?)
#:ports (listof number?)
#:listen-ip (or/c false/c string?)
#:max-waiting number?
#:initial-connection-timeout number?)
(-> void))]
[serve/ips+ports
(->* (#:dispatch dispatcher/c)
(#:tcp@ unit?
#:ips+ports (listof (cons/c (or/c false/c string?) (listof number?)))
#:max-waiting number?
#:initial-connection-timeout number?)
#:ips+ports (listof (cons/c (or/c false/c string?) (listof number?)))
#:max-waiting number?
#:initial-connection-timeout number?)
(-> void))]
[do-not-return (-> void)]
[serve/web-config@ ((unit?) (#:tcp@ unit?) . ->* . (-> void?))])
@ -59,7 +59,7 @@
dispatch-server@/tcp@
(import dispatch-server-config^)
(export dispatch-server^))
(serve))
(define (serve/ports

View File

@ -1,3 +1,16 @@
------------------------------
Version 4.3
------------------------------
. minor bug fixes
------------------------------
Version 4.2
------------------------------
. contract library's function contract
combinatiors now preserve tail recursion.
------------------------------
Version 4.1
------------------------------

View File

@ -1,6 +1,10 @@
Stepper
-------
Changes for v4.1.3:
Minor bug fixes.
Changes for v4.1.2:
None.

View File

@ -317,7 +317,6 @@ void wxMediaPasteboard::OnDefaultEvent(wxMouseEvent *event)
if (!admin)
return;
/* First, find clicked-on snip: */
x = event->x;
y = event->y;

View File

@ -889,8 +889,12 @@ int scheme_omittable_expr(Scheme_Object *o, int vals, int fuel, int resolved,
return 1;
}
}
/* (void <omittable> ...) */
if (SAME_OBJ(scheme_void_proc, app->args[0])) {
/* ({void,list,list*,vector,vector-immutable} <omittable> ...) */
if (SAME_OBJ(scheme_void_proc, app->args[0])
|| SAME_OBJ(scheme_list_proc, app->args[0])
|| SAME_OBJ(scheme_list_star_proc, app->args[0])
|| SAME_OBJ(scheme_vector_proc, app->args[0])
|| SAME_OBJ(scheme_vector_immutable_proc, app->args[0])) {
note_match(1, vals, warn_info);
if ((vals == 1) || (vals < 0)) {
int i;
@ -905,10 +909,15 @@ int scheme_omittable_expr(Scheme_Object *o, int vals, int fuel, int resolved,
}
if ((vtype == scheme_application2_type)) {
/* (values <omittable>) or (void <omittable>) */
/* ({values,void,list,list*,vector,vector-immutable,box} <omittable>) */
Scheme_App2_Rec *app = (Scheme_App2_Rec *)o;
if (SAME_OBJ(scheme_values_func, app->rator)
|| SAME_OBJ(scheme_void_proc, app->rator)) {
|| SAME_OBJ(scheme_void_proc, app->rator)
|| SAME_OBJ(scheme_list_proc, app->rator)
|| SAME_OBJ(scheme_list_star_proc, app->rator)
|| SAME_OBJ(scheme_vector_proc, app->rator)
|| SAME_OBJ(scheme_vector_immutable_proc, app->rator)
|| SAME_OBJ(scheme_box_proc, app->rator)) {
note_match(1, vals, warn_info);
if ((vals == 1) || (vals < 0)) {
if (scheme_omittable_expr(app->rand, 1, fuel - 1, resolved, warn_info))
@ -928,8 +937,14 @@ int scheme_omittable_expr(Scheme_Object *o, int vals, int fuel, int resolved,
return 1;
}
}
/* (void <omittable> <omittable>) */
if (SAME_OBJ(scheme_void_proc, app->rator)) {
/* ({void,cons,list,list*,vector,vector-immutable) <omittable> <omittable>) */
if (SAME_OBJ(scheme_void_proc, app->rator)
|| SAME_OBJ(scheme_cons_proc, app->rator)
|| SAME_OBJ(scheme_mcons_proc, app->rator)
|| SAME_OBJ(scheme_list_proc, app->rator)
|| SAME_OBJ(scheme_list_star_proc, app->rator)
|| SAME_OBJ(scheme_vector_proc, app->rator)
|| SAME_OBJ(scheme_vector_immutable_proc, app->rator)) {
note_match(1, vals, warn_info);
if ((vals == 1) || (vals < 0)) {
if (scheme_omittable_expr(app->rand1, 1, fuel - 1, resolved, warn_info)
@ -2507,7 +2522,8 @@ static Scheme_Object *optimize_application2(Scheme_Object *o, Optimize_Info *inf
}
}
if (SAME_OBJ(scheme_values_func, app->rator)
if ((SAME_OBJ(scheme_values_func, app->rator)
|| SAME_OBJ(scheme_list_star_proc, app->rator))
&& scheme_omittable_expr(app->rand, 1, -1, 0, info)) {
info->preserves_marks = 1;
info->single_result = 1;

View File

@ -1256,8 +1256,7 @@ static void *malloc_double(void)
#endif
#ifdef CAN_INLINE_ALLOC
static void *make_list_code;
# define make_list make_list_code
static void *make_list_code, *make_list_star_code;
#else
static Scheme_Object *make_list(long n)
{
@ -1270,6 +1269,17 @@ static Scheme_Object *make_list(long n)
return l;
}
static Scheme_Object *make_list_star(long n)
{
GC_CAN_IGNORE Scheme_Object **rs = MZ_RUNSTACK;
GC_CAN_IGNORE Scheme_Object *l = rs[--n];
while (n--) {
l = cons(rs[n], l);
}
return l;
}
#endif
#if !defined(CAN_INLINE_ALLOC)
@ -4077,6 +4087,13 @@ static int generate_inlined_unary(mz_jit_state *jitter, Scheme_App2_Rec *app, in
} else if (IS_NAMED_PRIM(rator, "vector-immutable")
|| IS_NAMED_PRIM(rator, "vector")) {
return generate_vector_alloc(jitter, rator, NULL, app, NULL);
} else if (IS_NAMED_PRIM(rator, "list*")) {
/* on a single argument, `list*' is identity */
mz_runstack_skipped(jitter, 1);
generate_non_tail(app->rand, jitter, 0, 1);
CHECK_LIMIT();
mz_runstack_unskipped(jitter, 1);
return 1;
} else if (IS_NAMED_PRIM(rator, "list")) {
mz_runstack_skipped(jitter, 1);
generate_non_tail(app->rand, jitter, 0, 1);
@ -4553,7 +4570,8 @@ static int generate_inlined_binary(mz_jit_state *jitter, Scheme_App3_Rec *app, i
(void)jit_movi_p(JIT_R0, scheme_void);
return 1;
} else if (IS_NAMED_PRIM(rator, "cons")) {
} else if (IS_NAMED_PRIM(rator, "cons")
|| IS_NAMED_PRIM(rator, "list*")) {
LOG_IT(("inlined cons\n"));
generate_two_args(app->rand1, app->rand2, jitter, 1);
@ -4748,8 +4766,12 @@ static int generate_inlined_nary(mz_jit_state *jitter, Scheme_App_Rec *app, int
} else if (IS_NAMED_PRIM(rator, "vector-immutable")
|| IS_NAMED_PRIM(rator, "vector")) {
return generate_vector_alloc(jitter, rator, app, NULL, NULL);
} else if (IS_NAMED_PRIM(rator, "list")) {
} else if (IS_NAMED_PRIM(rator, "list")
|| IS_NAMED_PRIM(rator, "list*")) {
int c = app->num_args;
int star;
star = IS_NAMED_PRIM(rator, "list*");
if (c)
generate_app(app, NULL, c, jitter, 0, 0, 1);
@ -4757,13 +4779,19 @@ static int generate_inlined_nary(mz_jit_state *jitter, Scheme_App_Rec *app, int
#ifdef CAN_INLINE_ALLOC
jit_movi_l(JIT_R2, c);
(void)jit_calli(make_list_code);
if (star)
(void)jit_calli(make_list_star_code);
else
(void)jit_calli(make_list_code);
#else
JIT_UPDATE_THREAD_RSPTR_IF_NEEDED();
jit_movi_l(JIT_R0, c);
mz_prepare(1);
jit_pusharg_l(JIT_R0);
(void)mz_finish(make_list);
if (star)
(void)mz_finish(make_list_star);
else
(void)mz_finish(make_list);
jit_retval(JIT_R0);
#endif
@ -7252,13 +7280,21 @@ static int do_generate_common(mz_jit_state *jitter, void *_data)
#ifdef CAN_INLINE_ALLOC
/* *** make_list_code *** */
/* R2 has length, args are on runstack */
{
for (i = 0; i < 2; i++) {
jit_insn *ref, *refnext;
make_list_code = jit_get_ip().ptr;
if (i == 0)
make_list_code = jit_get_ip().ptr;
else
make_list_star_code = jit_get_ip().ptr;
mz_prolog(JIT_R1);
jit_lshi_l(JIT_R2, JIT_R2, JIT_LOG_WORD_SIZE);
(void)jit_movi_p(JIT_R0, &scheme_null);
if (i == 0)
(void)jit_movi_p(JIT_R0, &scheme_null);
else {
jit_subi_l(JIT_R2, JIT_R2, JIT_WORD_SIZE);
jit_ldxr_p(JIT_R0, JIT_RUNSTACK, JIT_R2);
}
__START_SHORT_JUMPS__(1);
ref = jit_beqi_l(jit_forward(), JIT_R2, 0);

View File

@ -27,7 +27,11 @@
/* globals */
Scheme_Object scheme_null[1];
Scheme_Object *scheme_cons_proc;
Scheme_Object *scheme_mcons_proc;
Scheme_Object *scheme_list_proc;
Scheme_Object *scheme_list_star_proc;
Scheme_Object *scheme_box_proc;
/* locals */
static Scheme_Object *pair_p_prim (int argc, Scheme_Object *argv[]);
@ -155,7 +159,9 @@ scheme_init_list (Scheme_Env *env)
SCHEME_PRIM_PROC_FLAGS(p) |= SCHEME_PRIM_IS_UNARY_INLINED;
scheme_add_global_constant ("mpair?", p, env);
REGISTER_SO(scheme_cons_proc);
p = scheme_make_noncm_prim(cons_prim, "cons", 2, 2);
scheme_cons_proc = p;
SCHEME_PRIM_PROC_FLAGS(p) |= SCHEME_PRIM_IS_BINARY_INLINED;
scheme_add_global_constant ("cons", p, env);
@ -167,7 +173,9 @@ scheme_init_list (Scheme_Env *env)
SCHEME_PRIM_PROC_FLAGS(p) |= SCHEME_PRIM_IS_UNARY_INLINED;
scheme_add_global_constant ("cdr", p, env);
REGISTER_SO(scheme_mcons_proc);
p = scheme_make_noncm_prim(mcons_prim, "mcons", 2, 2);
scheme_mcons_proc = p;
SCHEME_PRIM_PROC_FLAGS(p) |= SCHEME_PRIM_IS_BINARY_INLINED;
scheme_add_global_constant ("mcons", p, env);
@ -205,11 +213,14 @@ scheme_init_list (Scheme_Env *env)
| SCHEME_PRIM_IS_NARY_INLINED);
scheme_add_global_constant ("list", p, env);
scheme_add_global_constant ("list*",
scheme_make_immed_prim(list_star_prim,
"list*",
1, -1),
env);
REGISTER_SO(scheme_list_star_proc);
p = scheme_make_immed_prim(list_star_prim, "list*", 1, -1);
scheme_list_star_proc = p;
SCHEME_PRIM_PROC_FLAGS(p) |= (SCHEME_PRIM_IS_UNARY_INLINED
| SCHEME_PRIM_IS_BINARY_INLINED
| SCHEME_PRIM_IS_NARY_INLINED);
scheme_add_global_constant ("list*", p, env);
scheme_add_global_constant("immutable?",
scheme_make_folding_prim(immutablep,
"immutable?",
@ -409,7 +420,9 @@ scheme_init_list (Scheme_Env *env)
1, 1, 1),
env);
REGISTER_SO(scheme_box_proc);
p = scheme_make_immed_prim(box, BOX, 1, 1);
scheme_box_proc = p;
SCHEME_PRIM_PROC_FLAGS(p) |= SCHEME_PRIM_IS_UNARY_INLINED;
scheme_add_global_constant(BOX, p, env);

View File

@ -4371,6 +4371,8 @@ static Scheme_Object *read_compact_k(void)
return read_compact(port, p->ku.k.i1);
}
int dump_info = 0;
static Scheme_Object *read_compact(CPort *port, int use_stack)
{
#define BLK_BUF_SIZE 32
@ -4396,6 +4398,9 @@ static Scheme_Object *read_compact(CPort *port, int use_stack)
ZO_CHECK(port->pos < port->size);
ch = CP_GETC(port);
if (dump_info)
printf("%d %d %d\n", ch, port->pos, need_car);
switch(cpt_branch[ch]) {
case CPT_ESCAPE:
{
@ -4451,6 +4456,8 @@ static Scheme_Object *read_compact(CPort *port, int use_stack)
case CPT_SYMREF:
l = read_compact_number(port);
RANGE_CHECK(l, < port->symtab_size);
if (dump_info)
printf("%d\n", l);
v = port->symtab[l];
if (!v) {
long save_pos = port->pos;
@ -5261,6 +5268,7 @@ static Scheme_Object *read_compiled(Scheme_Object *port,
len = symtabsize;
for (j = 1; j < len; j++) {
if (!symtab[j]) {
if (dump_info) printf("at %ld %ld\n", j, rp->pos);
v = read_compact(rp, 0);
symtab[j] = v;
} else {

View File

@ -260,7 +260,13 @@ void scheme_do_add_global_symbol(Scheme_Env *env, Scheme_Object *sym,
extern Scheme_Object *scheme_values_func;
extern Scheme_Object *scheme_procedure_p_proc;
extern Scheme_Object *scheme_void_proc;
extern Scheme_Object *scheme_cons_proc;
extern Scheme_Object *scheme_mcons_proc;
extern Scheme_Object *scheme_list_proc;
extern Scheme_Object *scheme_list_star_proc;
extern Scheme_Object *scheme_vector_proc;
extern Scheme_Object *scheme_vector_immutable_proc;
extern Scheme_Object *scheme_box_proc;
extern Scheme_Object *scheme_call_with_values_proc;
extern Scheme_Object *scheme_make_struct_type_proc;
extern Scheme_Object *scheme_current_inspector_proc;

View File

@ -25,6 +25,10 @@
#include "schpriv.h"
/* globals */
Scheme_Object *scheme_vector_proc;
Scheme_Object *scheme_vector_immutable_proc;
/* locals */
static Scheme_Object *vector_p (int argc, Scheme_Object *argv[]);
static Scheme_Object *make_vector (int argc, Scheme_Object *argv[]);
@ -53,13 +57,17 @@ scheme_init_vector (Scheme_Env *env)
1, 2),
env);
REGISTER_SO(scheme_vector_proc);
p = scheme_make_immed_prim(vector, "vector", 0, -1);
scheme_vector_proc = p;
SCHEME_PRIM_PROC_FLAGS(p) |= (SCHEME_PRIM_IS_UNARY_INLINED
| SCHEME_PRIM_IS_BINARY_INLINED
| SCHEME_PRIM_IS_NARY_INLINED);
scheme_add_global_constant("vector", p, env);
REGISTER_SO(scheme_vector_immutable_proc);
p = scheme_make_immed_prim(vector_immutable, "vector-immutable", 0, -1);
scheme_vector_immutable_proc = p;
SCHEME_PRIM_PROC_FLAGS(p) |= (SCHEME_PRIM_IS_UNARY_INLINED
| SCHEME_PRIM_IS_BINARY_INLINED
| SCHEME_PRIM_IS_NARY_INLINED);

View File

@ -533,6 +533,32 @@ void wxCanvasDC::DrawPoint(double x, double y)
if (!current_pen || current_pen->GetStyle() == wxTRANSPARENT)
return;
if (anti_alias) {
double xx, yy;
CGContextRef cg;
SetCurrentDC(TRUE);
cg = GetCG();
CGContextSaveGState(cg);
xx = SmoothingXFormX(x);
yy = SmoothingXFormY(y);
CGContextMoveToPoint(cg, xx, yy);
CGContextAddLineToPoint(cg, xx, yy);
wxMacSetCurrentTool(kPenTool);
CGContextStrokePath(cg);
wxMacSetCurrentTool(kNoTool);
CGContextRestoreGState(cg);
ReleaseCurrentDC();
return;
}
SetCurrentDC();
wxMacSetCurrentTool(kPenTool);
wxMacDrawPoint(XLOG2DEV(x), YLOG2DEV(y));