;;; man page -> HTML gateway for the SU web server. -*- Scheme -*- ;;; This file is part of the Scheme Untergrund Networking package. ;;; Copyright (c) 1996 by Mike Sperber. ;;; For copyright information, see the file COPYING which comes with ;;; the distribution. ;;; This uses RosettaMan and is currently based on version 2.5a6 ;;; (RosettaMan is based at ;;; ftp.cs.berkeley.edu:/ucb/people/phelps/tcltk/rman.tar.Z) ;(define rman/rman '("/afs/wsi/rs_aix41/bin/rman" -fHTML)) (define rman/man '(man)) (define rman/nroff '(nroff -man)) ;(define rman/gzcat '("/afs/wsi/rs_aix41/bin/zcat")) ;(define rman/zcat '("/afs/wsi/rs_aix41/bin/zcat")) (define rman/rman '("/usr/bin/rman" -fHTML)) (define rman/gzcat '("/usr/bin/zcat")) (define rman/zcat '("/usr/bin/zcat")) (define (rman-handler finder referencer address . maybe-man) (let ((parse-man-url (cond ((procedure? finder) finder) ((list? finder) (lambda (url) (values finder (unescape-uri (http-url:search url)) '()))) (else (let ((man-path ((infix-splitter ":") (getenv "MANPATH")))) (lambda (url) (values man-path (unescape-uri (http-url:search url)) '())))))) (reference-template (cond ((procedure? referencer) referencer) ((string? referencer) (lambda (entry section) referencer)) (else (lambda (entry section) "man?%s(%s)")))) (man (:optional maybe-man man))) (lambda (path req) (let ((request-method (request-method req))) (cond ((string=? request-method "GET") (with-fatal-error-handler (lambda (c decline) (cond ((http-error? c) (apply http-error (car (condition-stuff c)) req (cddr (condition-stuff c)))) (else (decline)))) (make-response http-status/ok (status-code->text http-status/ok) (time) "text/html" '() (make-writer-body (lambda (out options) (receive (man-path entry and-then) (parse-man-url (request-url req)) (emit-man-page entry man man-path and-then reference-template out)) (with-tag out address () (display address out))))))) (else (make-http-error-response http-status/method-not-allowed req request-method))))))) (define (cat-man-page key section out) (let ((title (if section (format #f "~a(~a) manual page" key section) (format #f "~a manual page" key)))) (emit-title out title) (emit-header out 1 title) (newline out) (with-tag out body () (with-tag out pre () (copy-inport->outport (current-input-port) out))))) (define (emit-man-page entry man man-path and-then reference-template out) (receive (key section) (parse-man-entry entry) (let ((status (cond ((procedure? and-then) (run (| (begin (man section key man-path)) (begin (and-then key section))) (= 1 ,out) (= 2 ,out))) (else (run (| (begin (man section key man-path)) (,@rman/rman ,@and-then -r ,(reference-template entry section))) (= 1 ,out) (= 2 ,out)))))) (if (not (zero? status)) (error "internal error emitting man page"))))) (define parse-man-entry (let ((entry-regexp (make-regexp "(.*)\\((.)\\)"))) (lambda (s) (cond ((regexp-exec entry-regexp s) => (lambda (match) (values (match:substring match 1) (match:substring match 2)))) (else (values s #f)))))) (define (man section key man-path) (cond ((procedure? man-path) (man-path)) ((find-man-file key section "cat" man-path) => cat-n-decode) ((find-man-file key section "man" man-path) => nroff-n-decode) (else (if (not (zero? (with-env (("MANPATH" . ,(string-join man-path ":"))) (run (,@rman/man ,@(if section `(,section) '()) ,key) stdports)))) (http-error http-status/not-found #f "man page not found"))))) (define man-default-sections '("1" "2" "3" "4" "5" "6" "7" "8" "9" "o" "l" "n" "p")) (define (find-man-file name section cat-man man-path . maybe-sections) (define (section-dir section) (lambda (dir) (file-name-as-directory (string-append (file-name-as-directory dir) cat-man section)))) (let* ((prefix (if section (string-append name "." section) (string-append name "."))) (pattern (string-append (glob-quote prefix) "*")) (sections (:optional maybe-sections man-default-sections)) (path (if section (map (section-dir section) man-path) (apply append (map (lambda (dir) (map (lambda (section) ((section-dir section) dir)) sections)) man-path))))) (let loop ((path path)) (and (not (null? path)) (let ((matches (glob (string-append (car path) pattern)))) (if (not (null? matches)) (car matches) (loop (cdr path)))))))) (define (file->man-directory file) (path-list->file-name (reverse (cdr (reverse (split-file-name (file-name-directory file))))))) (define (cat-n-decode file) (let ((ext (file-name-extension file))) (cond ((string=? ".gz" ext) (run (,@rman/gzcat ,file) stdports)) ((string=? ".Z" ext) (run (,@rman/zcat ,file) stdports)) (else (call-with-input-file file (lambda (port) (copy-inport->outport port (current-output-port)))))))) (define (nroff-n-decode file) (if (not (zero? (run (| (begin (cat-n-decode file)) (begin (with-cwd (file->man-directory file) (exec-epf (,@rman/nroff))))) stdports))) (http-error http-status/not-found #f "man page not found")))