;;;; -*-Scheme-*- ;;;; ;;;; $Revision: 1.5 $ ;;;; ;;;; General-purpose hypertext requests ;;;; ;;;; This implementation is undocumented and is likely to change in ;;;; future relases. (if (not (string=? (substitute "%format%") "html")) (quit "hypertext functions require -fhtml")) ;;; -------------------------------------------------------------------------- ;;; Data structures. (define ht-anchors '()) (define ht-references '()) (define anchor-name car) (define anchor-location cdr) (define (anchor-create name location) (cons name location)) (define ref-filename car) (define ref-offset cadr) (define ref-location caddr) (define ref-name cadddr) (define (ref-unresolved? x) (eqv? (ref-location x) "")) (define (set-ref-location! x l) (set-car! (cddr x) l)) (define (ref-create filename offset name) (list filename offset "" name)) ;;; -------------------------------------------------------------------------- ;;; Figure out if hypertext request is allowed at a given place and the ;;; filename to use in hypertext anchor. (define (default-query-anchor request label) (lambda (op) (case op (allowed? #t) (emit-anchor? #t) (filename (stream-target (output-stream)))))) (define (ht-querier request label) (let ((q (if (bound? 'query-anchor) query-anchor default-query-anchor))) (q request label))) ;;; -------------------------------------------------------------------------- ;;; Create hypertext anchor. ;;; ;;; .Ha label anchor-text (defmacro 'Ha (lambda (Ha name contents) (let* ((q (ht-querier '.Ha name)) (location (q 'filename))) (cond ((not (q 'allowed?)) "") ((assoc name ht-anchors) (warn ".Ha with duplicate anchor name `~a'" name)) (else (resolve-ht-reference name location) (list-push! ht-anchors (anchor-create name location)) (if (q 'emit-anchor?) (concat (format #f "~a" (parse-unquote name) (parse contents))) "")))))) (define (resolve-ht-reference name location) (let loop ((x ht-references)) (cond ((not (null? x)) (if (and (ref-unresolved? (car x)) (string=? (ref-name (car x)) name)) (set-ref-location! (car x) location)) (loop (cdr x)))))) ;;; -------------------------------------------------------------------------- ;;; Create hypertext reference. ;;; ;;; .Hr -url url anchor-text [suffix] ;;; .Hr -symbolic label anchor-text [suffix] ;;; .Hr troff-text (defmacro 'Hr (lambda (Hr type . args) (cond ((string=? type "-url") (if (< (length args) 2) (warn "too few arguments for .Hr") (concat (format #f "~a~a" (parse-unquote (car args)) (parse (cadr args)) (if (null? (cddr args)) #\newline (parse (caddr args) #\newline)))))) ((string=? type "-symbolic") (if (< (length args) 2) (warn "too few arguments for .Hr") (let* ((ref (car args)) (q (ht-querier '.Hr ref)) (filename (q 'filename)) (a (assoc ref ht-anchors)) (location (if a (cdr a) ""))) (cond ((not (q 'allowed?)) "") ((and (not a) (not (output-stream))) (warn ".Hr forward reference requires `document' option")) (else (emit "" (parse (cadr args)) "" (if (null? (cddr args)) #\newline (parse (caddr args) #\newline)))))))) (else "")))) ;;; -------------------------------------------------------------------------- ;;; Complain about unresolved references and weed out references that ;;; point into the file where they appear; then do the file insertions. (define (check-ht-references) (let loop ((x ht-references) (new '())) (cond ((null? x) new) ((ref-unresolved? (car x)) (warn "unresolved hypertext reference `~a' in file ~a" (ref-name (car x)) (ref-filename (car x))) (loop (cdr x) new)) ((string=? (ref-filename (car x)) (ref-location (car x))) (loop (cdr x) new)) (else (loop (cdr x) (cons (car x) new)))))) (define (insert-ht-references) (let ((refs (check-ht-references))) (file-insertions refs))) (defevent 'exit 90 insert-ht-references)