build without error
parent
017ff2377f
commit
959a1be5a1
@ -1,424 +0,0 @@
|
||||
; Binary parsing
|
||||
|
||||
;----------------------------------------
|
||||
; Apologia
|
||||
;
|
||||
; Binary parsing and unparsing are transformations between primitive or
|
||||
; composite Scheme values and their external binary representations.
|
||||
;
|
||||
; Examples include reading and writing JPEG, TIFF, MP3, ELF file
|
||||
; formats, communicating with DNS, Kerberos, LDAP, SLP internet
|
||||
; services, participating in Sun RPC and CORBA/IIOP distributed systems,
|
||||
; storing and retrieving (arrays of) floating-point numbers in a
|
||||
; portable and efficient way. This project will propose a set of low- and
|
||||
; intermediate- level procedures that make binary parsing possible.
|
||||
|
||||
; Scheme is a good language to do research in text compression. Text
|
||||
; compression involves a great deal of building and traversing
|
||||
; dictionaries, trees and similar data structures, where Scheme
|
||||
; excels. Performance doesn't matter in research, but the size of
|
||||
; compressed files does (to figure out the bpc for the common
|
||||
; benchmarks). Variable-bit i/o is a necessity. It is implemented
|
||||
; in the present file.
|
||||
|
||||
; ASN.1 corresponds to a higher-level parsing (LR parser
|
||||
; vs. lexer). Information in LDAP responses and X.509 certificates is
|
||||
; structural and recursive, and so lends itself to be processed in
|
||||
; Scheme. Variable bit i/o is necessary, and so is a binary lexer for
|
||||
; a LR parser. Parsing of ASN.1 is a highly profitable enterprise
|
||||
|
||||
;----------------------------------------
|
||||
; The outline of the project
|
||||
;
|
||||
; Primitives and streams
|
||||
;
|
||||
; - read-byte
|
||||
; - read-u8vector (cf. read-string)
|
||||
; - with-input-from-u8vector, with-input-from-encoded-u8vector 'base64,...
|
||||
; building binary i/o streams from a sequence of bytes. Streams over
|
||||
; u8vector, u16vector, etc. provide a serial access to memory. See SRFI-4
|
||||
;
|
||||
; - read-bit, read-bits via overlayed streams given read-byte
|
||||
; implemented in the present file.
|
||||
;
|
||||
; - mmap-u8vector, munmap-u8vector
|
||||
;
|
||||
; Conversions
|
||||
; - u8vector->integer u8vector endianness,
|
||||
; u8vector->sinteger u8vector endianness
|
||||
; These conversion procedures turn a sequence of bytes to an unsigned or
|
||||
; signed integer, minding the byte order. The u8vector in question can
|
||||
; have size 1,2,4,8, 3 etc. bytes. These two functions therefore can be
|
||||
; used to read shorts, longs, extra longs, etc. numbers.
|
||||
; - u8vector-reverse and other useful u8vector operations
|
||||
;
|
||||
; - modf, frexp, ldexp
|
||||
; The above primitives can be emulated in R5RS, yet they are quite handy
|
||||
; (for portable FP manipulation) and can be executed very efficiently by
|
||||
; an FPU.
|
||||
;
|
||||
; Higher-level parsing and combinators
|
||||
; These are combinators that can compose primitives above for more
|
||||
; complex (possibly iterative) actions.
|
||||
;
|
||||
; - skip-bits, next-u8token,...
|
||||
; - IIOP, RPC/XDR, RMI
|
||||
; - binary lexer for existing LR/LL-parsers
|
||||
;
|
||||
; The composition of primitives and combinators will represent binary
|
||||
; parsing language in a _full_ notation. This is similar to XPath
|
||||
; expressions in full notation. Later we need to find out the
|
||||
; most-frequently used patterns of the binary parsing language and
|
||||
; design an abbreviated notation. The latter will need a special
|
||||
; "interpreter". The abbreviated notation may turn out to look like
|
||||
; Olin's regular expressions.
|
||||
|
||||
; $Id: binary-read.scm,v 1.1 2000/10/20 17:49:47 oleg Exp oleg $
|
||||
|
||||
|
||||
;----------------------------------------
|
||||
; Test harness
|
||||
;
|
||||
; The following macro runs built-in test cases -- or does not run,
|
||||
; depending on which of the two lines below you commented out
|
||||
(define-macro (run-test . body) `(begin (display "\n-->Test\n") ,@body))
|
||||
;(define-macro (run-test . body) '(begin #f))
|
||||
;(defmacro run-test body `(begin (display "\n-->Test\n") ,@body))
|
||||
|
||||
;;========================================================================
|
||||
;; Configuration section
|
||||
;;
|
||||
; Performance is very important for binary parsing. We have to get all
|
||||
; help from a particular Scheme system we can get. If a Scheme function
|
||||
; can support the following primitives faster, we should take
|
||||
; advantage of that fact.
|
||||
|
||||
|
||||
;---
|
||||
; Configuration for Gambit. See below for other systems, as well as R5RS
|
||||
; implementations
|
||||
(declare
|
||||
(block)
|
||||
(standard-bindings)
|
||||
)
|
||||
|
||||
(define-macro (logior x y) `(##fixnum.logior ,x ,y))
|
||||
(define-macro (logand x y) `(##fixnum.logand ,x ,y))
|
||||
(define-macro (lsh-left x n) `(##fixnum.shl ,x ,n))
|
||||
(define-macro (lsh-right x n) `(##fixnum.lshr ,x ,n))
|
||||
(define-macro (lsh-left-one x) `(##fixnum.shl ,x 1))
|
||||
(define-macro (lsh-right-one x) `(##fixnum.lshr ,x 1))
|
||||
|
||||
(define-macro (-- x) `(##fixnum.- ,x 1))
|
||||
(define-macro (++ x) `(##fixnum.+ ,x 1))
|
||||
|
||||
(define-macro (bit-set? x mask) ; return x & mask != 0
|
||||
`(##not (##fixnum.zero? (logand ,x ,mask)))
|
||||
)
|
||||
; End of the Gambit-specific configuration section
|
||||
;---
|
||||
|
||||
; combine bytes in the MSB order. A byte may be #f
|
||||
(define (combine-two b1 b2) ; The result is for sure a fixnum
|
||||
(and b1 b2 (logior (lsh-left b1 8) b2)))
|
||||
|
||||
(define (combine-three b1 b2 b3) ; The result is for sure a fixnum
|
||||
(and b1 b2 b3 (logior (lsh-left (logior (lsh-left b1 8) b2) 8) b3)))
|
||||
|
||||
; Here the result may be a BIGNUM
|
||||
(define (combine-bytes . bytes)
|
||||
(cond
|
||||
((null? bytes) 0)
|
||||
((not (car bytes)) #f)
|
||||
(else
|
||||
(let loop ((bytes (cdr bytes)) (result (car bytes)))
|
||||
(cond
|
||||
((null? bytes) result)
|
||||
((not (car bytes)) #f)
|
||||
(else (loop (cdr bytes) (+ (car bytes) (* 256 result)))))))))
|
||||
|
||||
;---
|
||||
; R5RS implementations of the primitives
|
||||
; This is the most portable -- and the slowest implementation
|
||||
|
||||
; See also logical.scm from SLIB
|
||||
; (define (logior x y)
|
||||
; (cond ((= x y) x)
|
||||
; ((zero? x) y)
|
||||
; ((zero? y) x)
|
||||
; (else
|
||||
; (+ (* (logior (quotient x 2) (quotient y 2)) 2)
|
||||
; (if (and (even? x) (even? y)) 0 1)))))
|
||||
; (define (logand x y)
|
||||
; (cond ((= x y) x)
|
||||
; ((zero? x) 0)
|
||||
; ((zero? y) 0)
|
||||
; (else
|
||||
; (+ (* (logand (quotient x 2) (quotient y 2)) 2)
|
||||
; (if (or (even? x) (even? y)) 0 1)))))
|
||||
|
||||
; (define (lsh-left x n) (* x (expt 2 n)))
|
||||
; (define (lsh-right x n) (quotient x (expt 2 n)))
|
||||
; (define (lsh-left-one x) (* x 2))
|
||||
; (define (lsh-right-one x) (quotient x 2))
|
||||
|
||||
|
||||
; (define (-- x) (- x 1))
|
||||
; (define (++ x) (+ x 1))
|
||||
|
||||
; (define (bit-set? x mask) ; return x & mask != 0
|
||||
; (odd? (quotient x mask)) ; mask is an exact power of two
|
||||
; )
|
||||
|
||||
|
||||
;========================================================================
|
||||
; Reading a byte
|
||||
|
||||
; Read-byte is a fundamental primitive; it needs to be
|
||||
; added to the standard. Most of the other functions are library
|
||||
; procedures. The following is an approximation, which clearly doesn't
|
||||
; hold if the port is a Unicode (especially UTF-8) character stream.
|
||||
|
||||
; Return a byte as an exact integer [0,255], or the EOF object
|
||||
(define (read-byte port)
|
||||
(let ((c (read-char port)))
|
||||
(if (eof-object? c) c (char->integer c))))
|
||||
|
||||
; The same as above, but returns #f on EOF.
|
||||
(define (read-byte-f port)
|
||||
(let ((c (read-char port)))
|
||||
(and (not (eof-object? c)) (char->integer c))))
|
||||
|
||||
|
||||
|
||||
;========================================================================
|
||||
; Bit stream
|
||||
|
||||
; -- Function: make-bit-reader BYTE-READER
|
||||
|
||||
; Given a BYTE-READER (a thunk), construct and return a function
|
||||
; bit-reader N
|
||||
;
|
||||
; that reads N bits from a byte-stream represented by the BYTE-READER.
|
||||
; The BYTE-READER is a function that takes no arguments and returns
|
||||
; the current byte as an exact integer [0-255]. The byte reader
|
||||
; should return #f on EOF.
|
||||
; The bit reader returns N bits as an exact unsigned integer,
|
||||
; 0 -... (no limit). N must be a positive integer, otherwise the bit reader
|
||||
; returns #f. There is no upper limit on N -- other than the size of the
|
||||
; input stream itself and the amount of (virtual) memory an OS is willing
|
||||
; to give to your process. If you want to read 1M of _bits_, go ahead.
|
||||
;
|
||||
; It is assumed that the bit order is the most-significant bit first.
|
||||
;
|
||||
; Note the bit reader keeps the following condition true at all times:
|
||||
; (= current-inport-pos (ceiling (/ no-bits-read 8)))
|
||||
; That is, no byte is read until the very moment we really need (some of)
|
||||
; its bits. The bit reader does _not_ "byte read ahead".
|
||||
; Therefore, it can be used to handle a concatenation of different
|
||||
; bit/byte streams *STRICTLY* sequentially, _without_ 'backing up a char',
|
||||
; 'unreading-char' etc. tricks.
|
||||
; For example, make-bit-reader has been used to read GRIB files of
|
||||
; meteorological data, which made of several bitstreams with headers and
|
||||
; tags.
|
||||
; Thus careful attention to byte-buffering and optimization are the
|
||||
; features of this bit reader.
|
||||
;
|
||||
; Usage example:
|
||||
; (define bit-reader (make-bit-reader (lambda () #b11000101)))
|
||||
; (bit-reader 3) ==> 6
|
||||
; (bit-reader 4) ==> 2
|
||||
; The test driver below is another example.
|
||||
;
|
||||
; Notes on the algorithm.
|
||||
; The function recognizes and handles the following special cases:
|
||||
; - the buffer is empty and 8, 16, 24 bits are to be read
|
||||
; - reading all bits which are currently in the byte-buffer
|
||||
; (and then maybe more)
|
||||
; - reading only one bit
|
||||
|
||||
; Since the bit reader is going to be called many times, optimization is
|
||||
; critical. We need all the help from the compiler/interpreter
|
||||
; we can get.
|
||||
|
||||
|
||||
(define (make-bit-reader byte-reader)
|
||||
(let ((buffer 0) (mask 0) ; mask = 128 means that the buffer is full and
|
||||
; the msb bit is the current (yet unread) bit
|
||||
(bits-in-buffer 0))
|
||||
|
||||
; read the byte into the buffer and set up the counters.
|
||||
; return #f on eof
|
||||
(define (set-buffer)
|
||||
(set! buffer (byte-reader))
|
||||
(and buffer
|
||||
(begin
|
||||
(set! bits-in-buffer 8)
|
||||
(set! mask 128)
|
||||
#t)))
|
||||
|
||||
; Read fewer bits than there are in the buffer
|
||||
(define (read-few-bits n)
|
||||
(let ((value (logand buffer ; all bits in buffer
|
||||
(-- (lsh-left-one mask)))))
|
||||
(set! bits-in-buffer (- bits-in-buffer n))
|
||||
(set! mask (lsh-right mask n))
|
||||
(lsh-right value bits-in-buffer))) ; remove extra bits
|
||||
|
||||
; read n bits given an empty buffer, and append them to value, n>=8
|
||||
(define (add-more-bits value n)
|
||||
(let loop ((value value) (n n))
|
||||
(cond
|
||||
((zero? n) value)
|
||||
((< n 8)
|
||||
(let ((rest (read-n-bits n)))
|
||||
(and rest (+ (* value (lsh-left 1 n)) rest))))
|
||||
(else
|
||||
(let ((b (byte-reader)))
|
||||
(and b (loop (+ (* value 256) b) (- n 8))))))))
|
||||
|
||||
; The main module
|
||||
(define (read-n-bits n)
|
||||
; Check the most common cases first
|
||||
(cond
|
||||
((not (positive? n)) #f)
|
||||
((zero? bits-in-buffer) ; the bit-buffer is empty
|
||||
(case n
|
||||
((8) (byte-reader))
|
||||
((16)
|
||||
(let ((b (byte-reader)))
|
||||
(combine-two b (byte-reader))))
|
||||
((24)
|
||||
(let* ((b1 (byte-reader)) (b2 (byte-reader)))
|
||||
(combine-three b1 b2 (byte-reader))))
|
||||
(else
|
||||
(cond
|
||||
((< n 8)
|
||||
(and (set-buffer) (read-few-bits n)))
|
||||
((< n 16)
|
||||
(let ((b (byte-reader)))
|
||||
(and (set-buffer)
|
||||
(logior (lsh-left b (- n 8))
|
||||
(read-few-bits (- n 8))))))
|
||||
(else
|
||||
(let ((b (byte-reader)))
|
||||
(and b (add-more-bits b (- n 8)))))))))
|
||||
|
||||
((= n 1) ; read one bit
|
||||
(let ((value (if (bit-set? buffer mask) 1 0)))
|
||||
(set! mask (lsh-right-one mask))
|
||||
(set! bits-in-buffer (-- bits-in-buffer))
|
||||
value))
|
||||
|
||||
((>= n bits-in-buffer) ; will empty the buffer
|
||||
(let ((n-rem (- n bits-in-buffer))
|
||||
(value (logand buffer ; for mask=64, it'll be &63
|
||||
(-- (lsh-left-one mask)))))
|
||||
(set! bits-in-buffer 0)
|
||||
(cond
|
||||
((zero? n-rem) value)
|
||||
((<= n-rem 16)
|
||||
(let ((rest (read-n-bits n-rem)))
|
||||
(and rest (logior (lsh-left value n-rem) rest))))
|
||||
(else (add-more-bits value n-rem)))))
|
||||
(else (read-few-bits n))
|
||||
))
|
||||
|
||||
read-n-bits)
|
||||
)
|
||||
|
||||
|
||||
; Validation tests
|
||||
|
||||
(run-test
|
||||
(define (read-bits numbers nbits)
|
||||
(let* ((left-numbers numbers)
|
||||
(bit-reader
|
||||
(make-bit-reader
|
||||
(lambda ()
|
||||
(and (pair? left-numbers)
|
||||
(let ((byte (car left-numbers)))
|
||||
(set! left-numbers (cdr left-numbers))
|
||||
byte))))))
|
||||
(let loop ((result '()))
|
||||
(let ((num (bit-reader nbits)))
|
||||
(if num (loop (cons num result)) (reverse result))))))
|
||||
(define (do-test numbers nbits expected)
|
||||
(let ((result (read-bits numbers nbits)))
|
||||
(for-each display
|
||||
(list "Reading " numbers " by " nbits " bits\n"
|
||||
"The result is: " result "\n"))
|
||||
(or (equal? result expected)
|
||||
(error "the result differs from the expected: " expected))))
|
||||
|
||||
(do-test '(1 2 3 4 5 6 7) 8 '(1 2 3 4 5 6 7))
|
||||
(do-test '(193 5 131 4) 1
|
||||
'(1 1 0 0 0 0 0 1 0 0 0 0 0 1 0 1 1 0 0 0 0 0 1 1
|
||||
0 0 0 0 0 1 0 0))
|
||||
(do-test '(193 5 131 4 5) 2
|
||||
'(3 0 0 1 0 0 1 1 2 0 0 3 0 0 1 0 0 0 1 1))
|
||||
(do-test '(193 5 131 4) 3
|
||||
'(6 0 2 0 2 6 0 3 0 1))
|
||||
(do-test '(193 5 131 4 5 6 7) 4
|
||||
'(12 1 0 5 8 3 0 4 0 5 0 6 0 7))
|
||||
(do-test '(193 5 131 4 5 6 7) 5
|
||||
'(24 4 2 24 6 1 0 5 0 24 3))
|
||||
(do-test '(193 5 131 4 5 6 7 8 17 24) 8
|
||||
'(193 5 131 4 5 6 7 8 17 24))
|
||||
(do-test '(193 5 131 4 5 6 7 8 17 24) 9
|
||||
'(386 22 24 64 160 385 388 17))
|
||||
(do-test '(193 5 131 4 5 6 7 8 17) 16
|
||||
'(49413 33540 1286 1800))
|
||||
(do-test '(193 5 131 4 5 6 104) 17
|
||||
'(98827 3088 10291))
|
||||
(do-test '(193 5 131 4 5 6 104) 19
|
||||
'(395308 49409))
|
||||
(do-test '(193 5 131 4 5 6 104) 55
|
||||
'(27165365385724724))
|
||||
(do-test '(193 5 131 4 5 6 104) 56
|
||||
'(54330730771449448))
|
||||
)
|
||||
|
||||
|
||||
; Timing test
|
||||
; This test relies on a Gambit special form 'time' to clock
|
||||
; evaluation of an expression.
|
||||
; R5RS does not provide any timing facilities. So the test below
|
||||
; might not run on your particular system, and probably needs
|
||||
; adjustment anyway.
|
||||
|
||||
(run-test
|
||||
(let ((fname "/tmp/a") (size 10240)
|
||||
(pattern (integer->char #x55)))
|
||||
(define (read-by-bits n)
|
||||
(for-each display
|
||||
(list "Reading the file by " n " bits "))
|
||||
(call-with-input-file fname
|
||||
(lambda (port)
|
||||
(let ((bit-reader (make-bit-reader
|
||||
(lambda () (read-byte-f port)))))
|
||||
(time
|
||||
(do ((c (bit-reader n) (bit-reader n))) ((not c))))))))
|
||||
|
||||
(for-each display
|
||||
(list "Creating a file " fname " of size " size " filled with "
|
||||
pattern "\n"))
|
||||
(with-output-to-file fname
|
||||
(lambda () (do ((i 0 (+ 1 i))) ((>= i size)) (write-char pattern))))
|
||||
|
||||
(display "\nReading the file by characters: the baseline ")
|
||||
(call-with-input-file fname
|
||||
(lambda (port)
|
||||
(time
|
||||
(do ((c (read-char port) (read-char port))) ((eof-object? c))))))
|
||||
|
||||
(display "\nReading the file by bytes: ")
|
||||
(call-with-input-file fname
|
||||
(lambda (port)
|
||||
(time
|
||||
(do ((c (read-byte-f port) (read-byte-f port))) ((not c))))))
|
||||
|
||||
(for-each read-by-bits
|
||||
(list 1 2 3 4 5 6 7 8 9 10 11 15 16 17 23 24 25 30 32 65535
|
||||
(* 8 size)))
|
||||
))
|
Binary file not shown.
@ -1,98 +0,0 @@
|
||||
#lang br
|
||||
(require pitfall/binprint binparser racket/dict)
|
||||
|
||||
;; http://www.matthewflickinger.com/lab/whatsinagif/bits_and_bytes.asp
|
||||
|
||||
(define ip (open-input-file "sample.gif"))
|
||||
|
||||
|
||||
(define-rule gif-header (:seq [signature (:bytes 3 #:type string/ascii?)]
|
||||
[version (:bytes 3 #:type string/ascii?)]
|
||||
logical-screen-descriptor
|
||||
#:type assoc?))
|
||||
|
||||
(define-rule logical-screen-descriptor (:seq [width (:bytes 2 #:type integer?)]
|
||||
[height (:bytes 2 #:type integer?)]
|
||||
[lsd-flags (:bitfield [global-color-table-size (:bits 3 #:type integer?)]
|
||||
[sort (:bits 1 #:type boolean?)]
|
||||
[resolution (:bits 3 #:type integer?)]
|
||||
[global-color-table (:bits 1 #:type integer?)]
|
||||
#:type assoc?)]
|
||||
[bgcolor-idx (:bytes 1 #:type integer?)]
|
||||
[aspect (:bytes 1 #:type integer?)]
|
||||
#:type assoc?))
|
||||
|
||||
|
||||
|
||||
(define gh (gif-header ip))
|
||||
gh
|
||||
|
||||
(define (color-quantity table-size)
|
||||
(expt 2 (add1 table-size)))
|
||||
|
||||
|
||||
|
||||
(define-rule hex-color (:bytes 1 #:type hex?))
|
||||
(define-rule red hex-color)
|
||||
(define-rule green hex-color)
|
||||
(define-rule blue hex-color)
|
||||
(define-rule color (:seq red green blue))
|
||||
(define (global-color-quantity gh)
|
||||
(color-quantity (dict-ref* gh 'logical-screen-descriptor 'lsd-flags 'global-color-table)))
|
||||
(define-rule global-color-table (:repeat (global-color-quantity gh) color #:type assoc?))
|
||||
(define gct (global-color-table ip))
|
||||
|
||||
gct
|
||||
|
||||
(define-rule graphic-control-extension
|
||||
(:seq [extension-introducer (:bytes 1 #:type hex?)]
|
||||
[graphic-control-label (:bytes 1 #:type hex?)]
|
||||
[byte-size (:bytes 1 #:type integer?)]
|
||||
[gce-flags (:bitfield [transparent-color-flag (:bits 1 #:type boolean?)]
|
||||
[user-input-flag (:bits 1 #:type boolean?)]
|
||||
[disposal-method (:bits 3)]
|
||||
[reserved (:bits 3)]
|
||||
#:type assoc?)]
|
||||
[delay-time (:bytes 2 #:type integer?)]
|
||||
[transparent-color-idx (:bytes 1 #:type integer?)]
|
||||
[block-terminator (:bytes 1 #:type hex?)]
|
||||
#:type assoc?))
|
||||
|
||||
(graphic-control-extension ip)
|
||||
|
||||
|
||||
(define-rule image-descriptor
|
||||
(:seq [image-separator (:bytes 1 #:type hex?)]
|
||||
[left (:bytes 2 #:type integer?)]
|
||||
[top (:bytes 2 #:type integer?)]
|
||||
[width (:bytes 2 #:type integer?)]
|
||||
[height (:bytes 2 #:type integer?)]
|
||||
[id-flags (:seq [local-color-table-size (:bits 3 #:type integer?)]
|
||||
[reserved (:bits 2)]
|
||||
[sort-flag (:bits 1)]
|
||||
[interlace-flag (:bits 1)]
|
||||
[local-color-table-flag (:bits 1 #:type integer?)]
|
||||
#:type assoc?)]
|
||||
#:type assoc?))
|
||||
|
||||
(define img-descriptor (image-descriptor ip))
|
||||
|
||||
(define (local-color-quantity gh)
|
||||
(* (dict-ref* img-descriptor 'id-flags 'local-color-table-flag)
|
||||
(color-quantity (dict-ref* img-descriptor 'id-flags 'local-color-table-size))))
|
||||
(define-rule local-color-table (:repeat (local-color-quantity gh) color #:type assoc?))
|
||||
(define lct (local-color-table ip))
|
||||
|
||||
lct
|
||||
|
||||
(define-rule lzw-minimum-code-size (:bytes 1 #:type integer?))
|
||||
|
||||
(lzw-minimum-code-size ip)
|
||||
|
||||
(for/list ([block-len (in-port read-byte ip)]
|
||||
#:break (zero? block-len))
|
||||
((:bytes block-len #:type hex?) ip))
|
||||
|
||||
(define-rule trailer (:bytes 1 #:type hex?))
|
||||
|
||||
(trailer ip)
|
@ -1,26 +0,0 @@
|
||||
#lang br
|
||||
(require brag/support "gifparser.rkt")
|
||||
|
||||
(define the-lexer
|
||||
(lexer-srcloc
|
||||
[(eof) (return-without-srcloc eof)]
|
||||
["GIF" (token 'GIF-HEADER lexeme)]
|
||||
[any-char (token 'BYTE (char->integer (car (string->list lexeme))))]
|
||||
))
|
||||
|
||||
(define (make-tokenizer ip [path #f])
|
||||
(port-count-lines! ip)
|
||||
(lexer-file-path path)
|
||||
(λ () (the-lexer ip)))
|
||||
|
||||
(define (munge ip)
|
||||
(parse-to-datum (make-tokenizer (reencode-input-port ip "latin1"))))
|
||||
|
||||
|
||||
(module+ test
|
||||
(require pitfall/binprint)
|
||||
#;(binprint (open-input-file "test.gif") #:width 24)
|
||||
|
||||
#;(munge (open-input-bytes #"GIF87a1234567"))
|
||||
(munge (open-input-file "test.gif"))
|
||||
)
|
@ -1,26 +0,0 @@
|
||||
#lang brag
|
||||
|
||||
gif-file : header logical_screen u1*
|
||||
|
||||
header : magic version
|
||||
magic : GIF-HEADER
|
||||
version : u1 u1 u1
|
||||
|
||||
logical_screen : image_width image_height flags bg_color_index pixel_aspect_ratio
|
||||
image_width : u2le
|
||||
image_height :u2le
|
||||
flags : u1
|
||||
bg_color_index : u1
|
||||
pixel_aspect_ratio : u1
|
||||
u2le : BYTE BYTE
|
||||
u1 : BYTE
|
||||
|
||||
color_table : color_table_entry*
|
||||
color_table_entry : red green blue
|
||||
red : u1
|
||||
green : u1
|
||||
blue : u1
|
||||
|
||||
#block : block_type body
|
||||
#block_type : u1
|
||||
|
@ -1,310 +0,0 @@
|
||||
#lang sugar/debug racket/base
|
||||
(require sugar/debug)
|
||||
(require (for-syntax racket/base br/syntax))
|
||||
(require racket/match racket/function racket/port br/define sugar/list racket/list racket/bytes racket/string racket/dict)
|
||||
(provide (all-defined-out))
|
||||
|
||||
(define (dict-ref* d . keys)
|
||||
(foldl (λ (key d) (dict-ref d key)) d keys))
|
||||
|
||||
(define string/utf-8? #t)
|
||||
(define string/latin-1? 'string/latin-1?)
|
||||
(define string/ascii? 'string/ascii?)
|
||||
(define bitfield? (λ (x) (and (list? x) (andmap boolean? x))))
|
||||
|
||||
(define (assoc? x) (and (list? x) (andmap pair? x)))
|
||||
|
||||
(struct binary-problem (msg val) #:transparent)
|
||||
|
||||
(define bitfield #f)
|
||||
(define (reset-bitfield!) (set! bitfield #f))
|
||||
(define (read-bits-exact count p)
|
||||
(unless (pair? bitfield)
|
||||
(set! bitfield (bytes->bitfield (read-bytes 1 p))))
|
||||
(define-values (bits rest) (split-at bitfield count))
|
||||
(set! bitfield rest)
|
||||
bits)
|
||||
|
||||
(define (read-bytes-exact count p)
|
||||
(define bs (read-bytes count p))
|
||||
(unless (and (bytes? bs) (= (bytes-length bs) count))
|
||||
(raise (binary-problem (format "byte string length ~a" count) bs)))
|
||||
bs)
|
||||
|
||||
(define (bytes->integer len x #:endian [big-endian? #f])
|
||||
(when (< (bytes-length x) len) (raise-argument-error 'bytes->integer "too short" x))
|
||||
(cond
|
||||
[(= len 1) (bytes-ref x 0)]
|
||||
[else (define signed #f)
|
||||
(integer-bytes->integer x signed big-endian?)]))
|
||||
|
||||
(define (integer->bytes len x #:endian [big-endian? #f])
|
||||
(case len
|
||||
[(1) (bytes x)]
|
||||
[(2 4 8) (define signed #f)
|
||||
(integer->integer-bytes x len signed big-endian?)]
|
||||
[else (raise-argument-error 'integer->bytes "byte length 1 2 4 8" len)]))
|
||||
|
||||
(define integer/be? #t)
|
||||
(define (integer/be->bytes len x) (integer->bytes len x #:endian #t))
|
||||
(define (bytes->integer/be len x) (bytes->integer len x #:endian #t))
|
||||
|
||||
(require racket/format)
|
||||
(define (hex? x) (and (list? x) (andmap string? x)))
|
||||
(define (int->hex int) (~r int #:base 16 #:min-width 2 #:pad-string "0"))
|
||||
(define (hex->int hex) (string->number hex 16))
|
||||
|
||||
(define (bytes->ascii bs)
|
||||
(list->string (for/list ([b (in-bytes bs)])
|
||||
(if (< b 128)
|
||||
(integer->char b)
|
||||
(raise (binary-problem "ascii byte < 128" b))))))
|
||||
|
||||
(define (ascii->bytes str)
|
||||
(apply bytes (for/list ([c (in-string str)])
|
||||
(char->integer c))))
|
||||
|
||||
(define (bytes->bitfield bs)
|
||||
(for*/list ([b (in-bytes bs)]
|
||||
[idx (in-range 8)])
|
||||
(bitwise-bit-set? b idx)))
|
||||
|
||||
(define (bitfield->bytes bf)
|
||||
(unless (zero? (modulo (length bf) 8))
|
||||
(raise-argument-error 'bitfield->bytes "bitfield length a multiple of 8" (length bf)))
|
||||
(apply bytes
|
||||
(let loop ([bf bf][acc null])
|
||||
(if (null? bf)
|
||||
(reverse acc)
|
||||
(let-values ([(bits rest) (split-at bf 8)])
|
||||
(loop rest (cons (bitfield->integer bits) acc)))))))
|
||||
|
||||
(module+ test
|
||||
(check-equal? (bitfield->bytes (bytes->bitfield #"AB")) #"AB"))
|
||||
|
||||
(define (bitfield->integer bits)
|
||||
(for/sum ([b (in-list bits)]
|
||||
[pow (in-range 8)]
|
||||
#:when b)
|
||||
(expt 2 pow)))
|
||||
|
||||
(define (integer->bitfield len int)
|
||||
(define digits (reverse (string->list (number->string int 2))))
|
||||
(append (map (curry char=? #\1) digits) (make-list (- len (length digits)) #f)))
|
||||
|
||||
|
||||
(define bit? boolean?)
|
||||
|
||||
(define-macro-cases case-proc
|
||||
[(N PROC [TEST-PROC . EXPRS] ... [else . ELSE-EXPRS])
|
||||
#'(cond [(equal? PROC TEST-PROC) . EXPRS] ... [else . ELSE-EXPRS])]
|
||||
[(N ARG ...) #'(N ARG ... [else (void)])])
|
||||
|
||||
|
||||
(define (:bits count #:type [type list?])
|
||||
(procedure-rename
|
||||
(λ (x)
|
||||
(define-values (input-proc output-proc)
|
||||
(case-proc type
|
||||
[integer? (values bitfield->integer (curry integer->bitfield count))]
|
||||
[bitfield? (values bytes->bitfield bitfield->bytes)]
|
||||
[boolean?
|
||||
(unless (= 1 count)
|
||||
(raise-argument-error ':bits "boolean type only supported for 1-bit" count))
|
||||
(values (λ (bitfield) (car bitfield)) (λ (boolean) (list boolean)))]
|
||||
[list? (values identity identity)]
|
||||
[else (raise-argument-error ':bits "not a supported type" type)]))
|
||||
|
||||
(if (input-port? x)
|
||||
(input-proc (read-bits-exact count x))
|
||||
(let ([result (output-proc x)])
|
||||
(unless (and (andmap bit? result) (= (length result) count))
|
||||
(raise (binary-problem (format "bit string length ~a" count) result)))
|
||||
result))) (gensym 'bits-)))
|
||||
|
||||
(define (bytes->hexline bs)
|
||||
(string-join
|
||||
(for/list ([b (in-bytes bs)])
|
||||
(~r b #:base 16 #:min-width 2 #:pad-string "0")) " "))
|
||||
|
||||
(define (hexline->bytes hexline)
|
||||
(apply bytes (map (λ (str) (string->number str 16)) (string-split hexline))))
|
||||
|
||||
(module+ test
|
||||
(check-equal? (bytes->hexline #"ABC") "41 42 43")
|
||||
(check-equal? (hexline->bytes "41 42 43") #"ABC"))
|
||||
|
||||
|
||||
(define (:bytes count #:type [type bytes?])
|
||||
(procedure-rename
|
||||
(λ (x)
|
||||
(define-values (input-proc output-proc)
|
||||
(case-proc type
|
||||
[integer/be? (values (curry bytes->integer/be count)
|
||||
(curry integer/be->bytes count))]
|
||||
[integer? (values (curry bytes->integer count)
|
||||
(curry integer->bytes count))]
|
||||
[string/ascii? (values bytes->ascii ascii->bytes)]
|
||||
[string/utf-8? (values bytes->string/utf-8 string->bytes/utf-8)]
|
||||
[string/latin-1? (values bytes->string/latin-1 string->bytes/latin-1)]
|
||||
[bitfield? (values bytes->bitfield bitfield->bytes)]
|
||||
[bytes? (values identity identity)]
|
||||
[hex? (values bytes->hexline hexline->bytes)]
|
||||
[else (raise-argument-error ':bytes "not a supported type" type)]))
|
||||
|
||||
(if (input-port? x)
|
||||
(input-proc (read-bytes-exact count x))
|
||||
(let ([result (output-proc x)])
|
||||
(unless (and (bytes? result) (= (bytes-length result) count))
|
||||
(raise (binary-problem (format "byte string length ~a" count) result)))
|
||||
result))) (gensym 'bytes-)))
|
||||
|
||||
(define (list->hash-with-keys keys vals)
|
||||
(make-hash (list->dict-with-keys keys vals)))
|
||||
|
||||
(define (hash->list-with-keys keys h)
|
||||
(for/list ([k (in-list keys)])
|
||||
(hash-ref h k)))
|
||||
|
||||
(define (list->dict-with-keys keys vals)
|
||||
(map cons keys vals))
|
||||
|
||||
(define (procedure-name proc)
|
||||
(string->symbol (cadr (regexp-match #rx"^#<procedure:(.*?)>$" (with-output-to-string (λ () (display proc)))))))
|
||||
|
||||
(define (hash-has-keys? h keys)
|
||||
(define (sortation xs) (sort xs #:key symbol->string string<?))
|
||||
(equal? (sortation (hash-keys h)) (sortation keys)))
|
||||
|
||||
|
||||
(define (resolve-duplicates xs)
|
||||
(if (members-unique? xs)
|
||||
xs
|
||||
(for/list ([x (in-list xs)]
|
||||
[idx (in-naturals)])
|
||||
(string->symbol (format "~a-~a" x idx)))))
|
||||
|
||||
(define-for-syntax (process-rule-proc-args args)
|
||||
(pattern-case-filter args
|
||||
[(NAME RULE-PROC) #'(let () (define-rule NAME RULE-PROC) NAME)]
|
||||
[ELSE #'ELSE]))
|
||||
|
||||
(define-macro (define-seq-style-rule ID ID-INNER)
|
||||
#'(define-macro (ID . ARGS)
|
||||
#`(ID-INNER #,@(process-rule-proc-args #'ARGS))))
|
||||
|
||||
(define-seq-style-rule :bitfield bitfield-inner)
|
||||
|
||||
(define (bitfield-inner #:type [type list?] . rule-procs)
|
||||
((make-inner-proc (λ (xs) (let ([bf (append* xs)])
|
||||
(unless (zero? (modulo (length bf) 8))
|
||||
(raise-result-error ':bitfield (format "total field length is multiple of 8, got length ~a" (length bf)) bf))
|
||||
(bitfield->bytes bf))) 'bitfield) type rule-procs))
|
||||
|
||||
(define-seq-style-rule :seq seq-inner)
|
||||
|
||||
(define (seq-inner #:type [type list?] . rule-procs)
|
||||
((make-inner-proc bytes-append* ':seq) type rule-procs))
|
||||
|
||||
(define-macro (:repeat COUNT-EXPR . ARGS)
|
||||
#`(repeat-inner COUNT-EXPR #,@(process-rule-proc-args #'ARGS)))
|
||||
|
||||
(define (repeat-inner #:type [type list?] count . rule-procs)
|
||||
((make-inner-proc bytes-append* ':repeat) type (append* (make-list count rule-procs))))
|
||||
|
||||
(define (make-inner-proc post-proc sym)
|
||||
(λ (type rule-procs)
|
||||
(procedure-rename
|
||||
(λ (x) (define-values (input-proc output-proc output-check)
|
||||
(case-proc type
|
||||
[hash?
|
||||
(define rule-proc-names (resolve-duplicates (map procedure-name rule-procs)))
|
||||
(values (curry list->hash-with-keys rule-proc-names)
|
||||
(curry hash->list-with-keys rule-proc-names)
|
||||
(λ (x)
|
||||
(unless (and (hash? x) (hash-has-keys? x rule-proc-names))
|
||||
(raise (binary-problem (format "hash with ~a keys, namely ~a" (length rule-procs) rule-proc-names) x)))))]
|
||||
[list? (values identity identity
|
||||
(λ (x)
|
||||
(unless (and (list? x) (= (length rule-procs) (length x)))
|
||||
(raise (binary-problem (format "list of ~a values" (length rule-procs)) x)))))]
|
||||
[vector? (values list->vector vector->list
|
||||
(λ (x)
|
||||
(unless (and (vector? x) (= (length rule-procs) (vector-length x)))
|
||||
(raise (binary-problem (format "list of ~a values" (length rule-procs)) x)))))]
|
||||
[assoc?
|
||||
(define rule-proc-names (resolve-duplicates (map procedure-name rule-procs)))
|
||||
(values (curry list->dict-with-keys rule-proc-names) (λ (d) (map cdr d))
|
||||
(λ (x)
|
||||
(unless (and (assoc? x) (= (length rule-procs) (length x)))
|
||||
(raise (binary-problem (format "list of ~a values" (length rule-procs)) x)))))]
|
||||
[else (raise-argument-error sym "not a supported type" type)]))
|
||||
(match x
|
||||
[(? input-port? p) (input-proc (map (λ (rule-proc) (rule-proc p)) rule-procs))]
|
||||
[else
|
||||
(output-check x)
|
||||
(post-proc (map (λ (rp xi) (rp xi)) rule-procs (output-proc x)))])) (gensym sym))))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
(define-macro (define-rule ID RULE-PROC)
|
||||
#'(define (ID [x (current-input-port)])
|
||||
(with-handlers ([binary-problem? (λ (exn)
|
||||
(raise-result-error
|
||||
'ID
|
||||
(binary-problem-msg exn)
|
||||
(binary-problem-val exn)))])
|
||||
(RULE-PROC x))))
|
||||
|
||||
(define-macro (define-rules [ID RULE-PROC] ...)
|
||||
#'(begin (define-rule ID RULE-PROC) ...))
|
||||
|
||||
(define-macro (let-rule ([ID RULE-PROC] ...) . BODY)
|
||||
#'(let () (define ID RULE-PROC) ... . BODY))
|
||||
|
||||
(module+ test
|
||||
(require rackunit)
|
||||
|
||||
(define-rule foo (:seq bar zam #:type hash?))
|
||||
(define-rule bar (:bytes 1 #:type integer?))
|
||||
(define-rule zam (:bytes 2 #:type integer?))
|
||||
|
||||
(check-equal? #"AB" (zam (zam (open-input-bytes #"AB"))) (zam 16961))
|
||||
(check-equal? #"123" (foo (foo (open-input-bytes #"123"))) (foo '#hash((bar . 49) (zam . 13106))))
|
||||
|
||||
|
||||
(define-rule foolist (:seq bar zam bar zam))
|
||||
(check-equal? #"123456" (foolist (foolist (open-input-bytes #"123456"))) (foolist '(49 13106 52 13877)))
|
||||
|
||||
#|
|
||||
(define-rule bam (:bytes 1))
|
||||
(define-rule bams (:seq bam bam bam))
|
||||
(define-rule rebams (:seq (:bytes 1) (:bytes 1) (:bytes 1)))
|
||||
(check-equal? (bams (open-input-bytes #"ABC")) (rebams (open-input-bytes #"ABC")))
|
||||
|#
|
||||
|
||||
(define-rule hashrule (:seq bar zam bar zam bar #:type hash?))
|
||||
(check-equal? #"1234567" (hashrule (hashrule (open-input-bytes #"1234567")))
|
||||
(hashrule '#hash((zam-3 . 13877) (bar-2 . 52) (zam-1 . 13106) (bar-0 . 49) (bar-4 . 55))))
|
||||
|
||||
|
||||
(define-rule flag8 (:bits 8))
|
||||
(check-equal? (flag8 (open-input-bytes #"A")) '(#t #f #f #f #f #f #t #f))
|
||||
|
||||
(define-rule flag4 (:bits 4))
|
||||
(check-equal? (flag4 (open-input-bytes #"A")) '(#t #f #f #f))
|
||||
|
||||
(reset-bitfield!)
|
||||
(define-rule bitint (:bits 8 #:type integer?))
|
||||
(check-equal? (bitint (open-input-bytes #"A")) 65)
|
||||
(check-equal? (bitint 65) '(#t #f #f #f #f #f #t #f))
|
||||
|
||||
|
||||
(reset-bitfield!)
|
||||
(define-rule thing (:bytes 1))
|
||||
(define-rule rpt (:repeat 3 thing)) ; repeat has to use other identifier names, not direct rule procs
|
||||
(check-equal? (rpt (rpt (open-input-bytes #"ABC"))) #"ABC")
|
||||
|
||||
)
|
@ -1,85 +0,0 @@
|
||||
#lang br
|
||||
|
||||
(define (read-bytes-exact count p)
|
||||
(define bs (read-bytes count p))
|
||||
(unless (and (bytes? bs) (= (bytes-length bs) count))
|
||||
(raise-argument-error 'read-bytes-exact (format "byte string length ~a" count) bs))
|
||||
bs)
|
||||
|
||||
(define BinaryIO%
|
||||
(class object%
|
||||
(super-new)
|
||||
(abstract decode)
|
||||
(abstract encode)
|
||||
(abstract size)))
|
||||
|
||||
|
||||
(define ByteIO%
|
||||
(class BinaryIO%
|
||||
(super-new)
|
||||
(init-field [_count 1])
|
||||
(field [_bytes null])
|
||||
|
||||
(define/override (decode ip)
|
||||
(set! _bytes (read-bytes-exact _count ip)))
|
||||
|
||||
(define/override (encode op val) (write-bytes _bytes op))
|
||||
|
||||
(define/override (size) (bytes-length _bytes))))
|
||||
|
||||
(define b (make-object ByteIO%))
|
||||
|
||||
(define ip (open-input-bytes #"ABC"))
|
||||
|
||||
(send b decode ip)
|
||||
|
||||
(define-macro (define-subclass SUPERCLASS (ID . INIT-ARGS) . BODY)
|
||||
#'(define ID (class SUPERCLASS (super-new) (init-field . INIT-ARGS) . BODY)))
|
||||
|
||||
(define-macro (getter-field [ID . EXPRS])
|
||||
(with-pattern ([_ID (prefix-id "_" #'ID)])
|
||||
#'(begin
|
||||
(field [(ID _ID) . EXPRS])
|
||||
(public (_ID ID))
|
||||
(define (_ID) ID))))
|
||||
|
||||
(define (ends-with-8? type)
|
||||
(equal? (substring type (sub1 (string-length type))) "8"))
|
||||
|
||||
(define-subclass BinaryIO% (NumberT type [endian (if (system-big-endian?) 'BE 'LE)])
|
||||
(getter-field [fn (format "~a~a" type (if (ends-with-8? type)
|
||||
""
|
||||
endian))])
|
||||
|
||||
(define/override (decode ip) 'foo)
|
||||
|
||||
(define/override (encode op val) 'foo)
|
||||
|
||||
(define/override (size) 'foo))
|
||||
|
||||
|
||||
(define o (make-object NumberT "UInt16"))
|
||||
|
||||
(send o fn)
|
||||
|
||||
|
||||
|
||||
|
||||
#|
|
||||
(define uint32be (:bytes 4 #:type integer/be?))
|
||||
(define uint16be (:bytes 2 #:type integer/be?))
|
||||
(define hexbytes (:bytes 4 #:type hex?))
|
||||
(define (:make-string count) (:bytes count #:type string/ascii?))
|
||||
|
||||
(require (for-syntax sugar/debug))
|
||||
(define-macro (:seq ([ID BINDING . MAYBE-GUARD] ...) . BODY)
|
||||
(with-pattern ([(GUARD ...) (pattern-case-filter #'(MAYBE-GUARD ...)
|
||||
[(#:assert PRED) #'(λ (x) (unless (PRED x) (error 'assert-failed)))]
|
||||
[ELSE #'void])])
|
||||
#'(λ (p) (let* ([ID (let ([ID (BINDING p)])
|
||||
(GUARD ID)
|
||||
ID)] ...)
|
||||
(begin . BODY)
|
||||
(list (cons 'ID ID) ...)))))
|
||||
|
||||
|#
|
@ -1,47 +0,0 @@
|
||||
#lang br
|
||||
|
||||
|
||||
gif-file : header logical-screen-descriptor global-color-table middle trailer
|
||||
header : signature version
|
||||
signature : #"GIF"
|
||||
version : u1{3} => bytes->string
|
||||
logical-screen-descriptor : width height packed bgcolor-idx aspect
|
||||
width : u2
|
||||
height : u2
|
||||
packed : color-table-flag color-res sort-flag color-table-size
|
||||
bgcolor-idx : u1
|
||||
aspect : u1
|
||||
|
||||
color-table-flag : b{1} => ->integer
|
||||
color-res : b{3}
|
||||
sort-flag : b{1}
|
||||
color-table-size : b{3}
|
||||
|
||||
color-table-colors (size->colors color-table-size)
|
||||
|
||||
global-color-table : color-rec{color-table-flag * color-table-colors}
|
||||
color-rec : red green blue
|
||||
red : u1
|
||||
blue : u1
|
||||
green : u1
|
||||
|
||||
middle: gfx-control-ext img-descriptor lct? image-data
|
||||
|
||||
gfx-control-ext : u1{8}
|
||||
img-descriptor : img-separator left top width height img-packed
|
||||
|
||||
img-separator : #"2C"
|
||||
left : u2
|
||||
top : u2
|
||||
width : u2
|
||||
height : u2
|
||||
img-packed : lct-flag interlace sort res lct-size
|
||||
lct-flag : b
|
||||
interlace : b
|
||||
sort : b
|
||||
res : b{2}
|
||||
lct-size : b{3}
|
||||
|
||||
lct: color-rec{lct-flag * (size->colors lct-size)}
|
||||
|
||||
image-data : lzw-size data-subblock
|
Binary file not shown.
Before Width: | Height: | Size: 69 B |
Binary file not shown.
Before Width: | Height: | Size: 1.5 KiB |
@ -1,7 +1,14 @@
|
||||
#lang info
|
||||
(define collection 'multi)
|
||||
(define deps '("base" "rackunit-lib"))
|
||||
(define deps '("at-exp-lib"
|
||||
"beautiful-racket-lib"
|
||||
"brag"
|
||||
"describe"
|
||||
"png-image"
|
||||
"srfi-lite-lib"
|
||||
"sugar"
|
||||
"base" "rackunit-lib"))
|
||||
(define build-deps '("scribble-lib" "racket-doc"))
|
||||
(define version "0.0")
|
||||
(define pkg-authors '(mb))
|
||||
(define compile-omit-paths '("pitfall/test/node_modules/pdfkit"))
|
||||
(define compile-omit-paths '("pdfkit" "fontkit"))
|
@ -1,3 +1,2 @@
|
||||
#lang info
|
||||
|
||||
(define compile-omit-paths '("old"))
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,324 @@
|
||||
/* See the beginning of "manual.css". */
|
||||
|
||||
/* Monospace: */
|
||||
|
||||
.RktIn, .RktRdr, .RktPn, .RktMeta,
|
||||
.RktMod, .RktKw, .RktVar, .RktSym,
|
||||
.RktRes, .RktOut, .RktCmt, .RktVal,
|
||||
.RktBlk, .RktErr {
|
||||
font-family: 'Fira-Mono', monospace;
|
||||
white-space: inherit;
|
||||
font-size: 1rem;
|
||||
line-height: 1.5;
|
||||
|
||||
}
|
||||
|
||||
/* this selctor grabs the first linked Racket symbol
|
||||
in a definition box (i.e., the symbol being defined) */
|
||||
a.RktValDef, a.RktStxDef, a.RktSymDef,
|
||||
span.RktValDef, span.RktStxDef, span.RktSymDef
|
||||
{
|
||||
font-size: 1.1rem;
|
||||
color: black;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
|
||||
.inheritedlbl {
|
||||
font-family: 'Fira', sans-serif;
|
||||
}
|
||||
|
||||
.RBackgroundLabelInner {
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
/* ---------------------------------------- */
|
||||
/* Inherited methods, left margin */
|
||||
|
||||
.inherited {
|
||||
width: 95%;
|
||||
margin-top: 0.5em;
|
||||
text-align: left;
|
||||
background-color: inherit;
|
||||
}
|
||||
|
||||
.inherited td {
|
||||
font-size: 82%;
|
||||
padding-left: 0.5rem;
|
||||
line-height: 1.3;
|
||||
text-indent: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.inheritedlbl {
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/* ---------------------------------------- */
|
||||
/* Racket text styles */
|
||||
|
||||
.RktIn {
|
||||
color: #cc6633;
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
.RktInBG {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
|
||||
.refcolumn .RktInBG {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.RktRdr {
|
||||
}
|
||||
|
||||
.RktPn {
|
||||
color: #843c24;
|
||||
}
|
||||
|
||||
.RktMeta {
|
||||
color: black;
|
||||
}
|
||||
|
||||
.RktMod {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.RktOpt {
|
||||
color: black;
|
||||
}
|
||||
|
||||
.RktKw {
|
||||
color: black;
|
||||
}
|
||||
|
||||
.RktErr {
|
||||
color: red;
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.RktVar {
|
||||
position: relative;
|
||||
left: -1px; font-style: italic;
|
||||
color: #444;
|
||||
}
|
||||
|
||||
.SVInsetFlow .RktVar {
|
||||
font-weight: 400;
|
||||
color: #444;
|
||||
}
|
||||
|
||||
|
||||
.RktSym {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.RktValLink, .RktStxLink, .RktModLink {
|
||||
text-decoration: none;
|
||||
color: #07A;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
/* for syntax links within headings */
|
||||
h2 a.RktStxLink, h3 a.RktStxLink, h4 a.RktStxLink, h5 a.RktStxLink,
|
||||
h2 a.RktValLink, h3 a.RktValLink, h4 a.RktValLink, h5 a.RktValLink,
|
||||
h2 .RktSym, h3 .RktSym, h4 .RktSym, h5 .RktSym,
|
||||
h2 .RktMod, h3 .RktMod, h4 .RktMod, h5 .RktMod,
|
||||
h2 .RktVal, h3 .RktVal, h4 .RktVal, h5 .RktVal,
|
||||
h2 .RktPn, h3 .RktPn, h4 .RktPn, h5 .RktPn {
|
||||
color: #333;
|
||||
font-size: 1.50rem;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.toptoclink .RktStxLink, .toclink .RktStxLink,
|
||||
.toptoclink .RktValLink, .toclink .RktValLink,
|
||||
.toptoclink .RktModLink, .toclink .RktModLink {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.tocset .RktValLink, .tocset .RktStxLink, .tocset .RktModLink, .tocset .RktSym {
|
||||
color: black;
|
||||
font-weight: 400;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.tocset td a.tocviewselflink .RktValLink,
|
||||
.tocset td a.tocviewselflink .RktStxLink,
|
||||
.tocset td a.tocviewselflink .RktMod,
|
||||
.tocset td a.tocviewselflink .RktSym {
|
||||
font-weight: lighter;
|
||||
color: white;
|
||||
}
|
||||
|
||||
|
||||
.RktRes {
|
||||
color: #0000af;
|
||||
}
|
||||
|
||||
.RktOut {
|
||||
color: #960096;
|
||||
}
|
||||
|
||||
.RktCmt {
|
||||
color: #c2741f;
|
||||
}
|
||||
|
||||
.RktVal {
|
||||
color: #228b22;
|
||||
}
|
||||
|
||||
/* ---------------------------------------- */
|
||||
/* Some inline styles */
|
||||
|
||||
.together { /* for definitions grouped together in one box */
|
||||
width: 100%;
|
||||
border-top: 2px solid white;
|
||||
}
|
||||
|
||||
tbody > tr:first-child > td > .together {
|
||||
border-top: 0px; /* erase border on first instance of together */
|
||||
}
|
||||
|
||||
.RktBlk {
|
||||
white-space: pre;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.highlighted {
|
||||
font-size: 1rem;
|
||||
background-color: #fee;
|
||||
}
|
||||
|
||||
.defmodule {
|
||||
font-family: 'Fira-Mono', monospace;
|
||||
padding: 0.25rem 0.75rem 0.25rem 0.5rem;
|
||||
margin-bottom: 1rem;
|
||||
width: 100%;
|
||||
background-color: #ebf0f4;
|
||||
}
|
||||
|
||||
.defmodule a {
|
||||
color: #444;
|
||||
}
|
||||
|
||||
|
||||
.defmodule td span.hspace:first-child {
|
||||
position: absolute;
|
||||
width: 0;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.defmodule .RpackageSpec .Smaller,
|
||||
.defmodule .RpackageSpec .stt {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
/* make parens ordinary color in defmodule */
|
||||
.defmodule .RktPn {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.specgrammar {
|
||||
float: none;
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
|
||||
.RBibliography td {
|
||||
vertical-align: text-top;
|
||||
padding-top: 1em;
|
||||
}
|
||||
|
||||
.leftindent {
|
||||
margin-left: 2rem;
|
||||
margin-right: 0em;
|
||||
}
|
||||
|
||||
.insetpara {
|
||||
margin-left: 1em;
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
.SCodeFlow .Rfilebox {
|
||||
margin-left: -1em; /* see 17.2 of guide, module languages */
|
||||
}
|
||||
|
||||
.Rfiletitle {
|
||||
text-align: right;
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
.SCodeFlow .Rfiletitle {
|
||||
border-top: 1px dotted gray;
|
||||
border-right: 1px dotted gray;
|
||||
}
|
||||
|
||||
|
||||
.Rfilename {
|
||||
border-top: 0;
|
||||
border-right: 0;
|
||||
padding-left: 0.5em;
|
||||
padding-right: 0.5em;
|
||||
background-color: inherit;
|
||||
}
|
||||
|
||||
.Rfilecontent {
|
||||
margin: 0.5em;
|
||||
}
|
||||
|
||||
.RpackageSpec {
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
/* ---------------------------------------- */
|
||||
/* For background labels */
|
||||
|
||||
.RBackgroundLabel {
|
||||
float: right;
|
||||
width: 0px;
|
||||
height: 0px;
|
||||
}
|
||||
|
||||
.RBackgroundLabelInner {
|
||||
position: relative;
|
||||
width: 25em;
|
||||
left: -25.5em;
|
||||
top: 0.20rem; /* sensitive to monospaced font choice */
|
||||
text-align: right;
|
||||
z-index: 0;
|
||||
font-weight: 300;
|
||||
font-family: 'Fira-Mono', monospace;
|
||||
font-size: 0.9rem;
|
||||
color: gray;
|
||||
}
|
||||
|
||||
|
||||
.RpackageSpec .Smaller {
|
||||
font-weight: 300;
|
||||
font-family: 'Fira-Mono', monospace;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.RForeground {
|
||||
position: relative;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* ---------------------------------------- */
|
||||
/* For section source modules & tags */
|
||||
|
||||
.RPartExplain {
|
||||
background: #eee;
|
||||
font-size: 0.9rem;
|
||||
margin-top: 0.2rem;
|
||||
padding: 0.2rem;
|
||||
text-align: left;
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
/* For the Racket manual style */
|
||||
|
||||
AddOnLoad(function() {
|
||||
/* Look for header elements that have x-source-module and x-part tag.
|
||||
For those elements, add a hidden element that explains how to
|
||||
link to the section, and set the element's onclick() to display
|
||||
the explanation. */
|
||||
var tag_names = ["h1", "h2", "h3", "h4", "h5"];
|
||||
for (var j = 0; j < tag_names.length; j++) {
|
||||
elems = document.getElementsByTagName(tag_names[j]);
|
||||
for (var i = 0; i < elems.length; i++) {
|
||||
var elem = elems.item(i);
|
||||
AddPartTitleOnClick(elem);
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
function AddPartTitleOnClick(elem) {
|
||||
var mod_path = elem.getAttribute("x-source-module");
|
||||
var tag = elem.getAttribute("x-part-tag");
|
||||
if (mod_path && tag) {
|
||||
// Might not be present:
|
||||
var prefixes = elem.getAttribute("x-part-prefixes");
|
||||
|
||||
var info = document.createElement("div");
|
||||
info.className = "RPartExplain";
|
||||
|
||||
/* The "top" tag refers to a whole document: */
|
||||
var is_top = (tag == "\"top\"");
|
||||
info.appendChild(document.createTextNode("Link to this "
|
||||
+ (is_top ? "document" : "section")
|
||||
+ " with "));
|
||||
|
||||
/* Break `secref` into two lines if the module path and tag
|
||||
are long enough: */
|
||||
var is_long = (is_top ? false : ((mod_path.length
|
||||
+ tag.length
|
||||
+ (prefixes ? (16 + prefixes.length) : 0))
|
||||
> 60));
|
||||
|
||||
var line1 = document.createElement("div");
|
||||
var line1x = ((is_long && prefixes) ? document.createElement("div") : line1);
|
||||
var line2 = (is_long ? document.createElement("div") : line1);
|
||||
|
||||
function add(dest, str, cn) {
|
||||
var s = document.createElement("span");
|
||||
s.className = cn;
|
||||
s.style.whiteSpace = "nowrap";
|
||||
s.appendChild(document.createTextNode(str));
|
||||
dest.appendChild(s);
|
||||
}
|
||||
/* Construct a `secref` call with suitable syntax coloring: */
|
||||
add(line1, "\xA0@", "RktRdr");
|
||||
add(line1, (is_top ? "other-doc" : "secref"), "RktSym");
|
||||
add(line1, "[", "RktPn");
|
||||
if (!is_top)
|
||||
add(line1, tag, "RktVal");
|
||||
if (is_long) {
|
||||
/* indent additional lines: */
|
||||
if (prefixes)
|
||||
add(line1x, "\xA0\xA0\xA0\xA0\xA0\xA0\xA0\xA0", "RktPn");
|
||||
add(line2, "\xA0\xA0\xA0\xA0\xA0\xA0\xA0\xA0", "RktPn");
|
||||
}
|
||||
if (prefixes) {
|
||||
add(line1x, " #:tag-prefixes ", "RktPn");
|
||||
add(line1x, "'", "RktVal");
|
||||
add(line1x, prefixes, "RktVal");
|
||||
}
|
||||
if (!is_top)
|
||||
add(line2, " #:doc ", "RktPn");
|
||||
add(line2, "'", "RktVal");
|
||||
add(line2, mod_path, "RktVal");
|
||||
add(line2, "]", "RktPn");
|
||||
|
||||
info.appendChild(line1);
|
||||
if (is_long)
|
||||
info.appendChild(line1x);
|
||||
if (is_long)
|
||||
info.appendChild(line2);
|
||||
|
||||
info.style.display = "none";
|
||||
|
||||
/* Add the new element afterthe header: */
|
||||
var n = elem.nextSibling;
|
||||
if (n)
|
||||
elem.parentNode.insertBefore(info, n);
|
||||
else
|
||||
elem.parentNode.appendChild(info);
|
||||
|
||||
/* Clicking the header shows the explanation element: */
|
||||
elem.onclick = function () {
|
||||
if (info.style.display == "none")
|
||||
info.style.display = "block";
|
||||
else
|
||||
info.style.display = "none";
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,770 @@
|
||||
|
||||
/* See the beginning of "scribble.css".
|
||||
This file is used by the `scribble/manual` language, along with
|
||||
"manual-racket.css". */
|
||||
|
||||
@import url("manual-fonts.css");
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
@media all {html {font-size: 15px;}}
|
||||
@media all and (max-width:940px){html {font-size: 14px;}}
|
||||
@media all and (max-width:850px){html {font-size: 13px;}}
|
||||
@media all and (max-width:830px){html {font-size: 12px;}}
|
||||
@media all and (max-width:740px){html {font-size: 11px;}}
|
||||
|
||||
/* CSS seems backward: List all the classes for which we want a
|
||||
particular font, so that the font can be changed in one place. (It
|
||||
would be nicer to reference a font definition from all the places
|
||||
that we want it.)
|
||||
|
||||
As you read the rest of the file, remember to double-check here to
|
||||
see if any font is set. */
|
||||
|
||||
/* Monospace: */
|
||||
.maincolumn, .refpara, .refelem, .tocset, .stt, .hspace, .refparaleft, .refelemleft {
|
||||
font-family: 'Fira-Mono', monospace;
|
||||
white-space: inherit;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
/* embolden the "Racket Guide" and "Racket Reference" links on the TOC */
|
||||
/* there isn't an obvious tag in the markup that designates the top TOC page, which is called "start.scrbl" */
|
||||
/* nor a tag that designates these two links as special */
|
||||
/* so we'll use this slightly tortured sibling selector that hooks onto the h2 tag */
|
||||
h2[x-source-module='(lib "scribblings/main/start.scrbl")'] ~ table a[href="guide/index.html"],
|
||||
h2[x-source-module='(lib "scribblings/main/start.scrbl")'] ~ table a[href="reference/index.html"] {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
h2 .stt {
|
||||
font-size: 2.3rem;
|
||||
/* prevent automatic bolding from h2 */
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.toptoclink .stt {
|
||||
font-size: inherit;
|
||||
}
|
||||
.toclink .stt {
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
.RpackageSpec .stt {
|
||||
font-weight: 300;
|
||||
font-family: 'Fira-Mono', monospace;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
h3 .stt, h4 .stt, h5 .stt {
|
||||
color: #333;
|
||||
font-size: 1.65rem;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
|
||||
/* Serif: */
|
||||
.main, .refcontent, .tocview, .tocsub, .sroman, i {
|
||||
font-family: 'Charter-Racket', serif;
|
||||
font-size: 1.18rem;
|
||||
/* Don't use font-feature-settings with Charter,
|
||||
it fouls up loading for reasons mysterious */
|
||||
/* font-feature-settings: 'tnum' 1, 'liga' 0; */
|
||||
}
|
||||
|
||||
|
||||
/* Sans-serif: */
|
||||
.version, .versionNoNav, .ssansserif {
|
||||
font-family: 'Fira', sans-serif;
|
||||
}
|
||||
|
||||
/* used mostly for DrRacket menu commands */
|
||||
.ssansserif {
|
||||
font-family: 'Fira', sans-serif;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.tocset .ssansserif {
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
/* ---------------------------------------- */
|
||||
|
||||
p, .SIntrapara {
|
||||
display: block;
|
||||
margin: 0 0 1em 0;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.compact {
|
||||
padding: 0 0 1em 0;
|
||||
}
|
||||
|
||||
li {
|
||||
list-style-position: outside;
|
||||
margin-left: 1.2em;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6, h7, h8 {
|
||||
font-family: 'Fira', sans-serif;
|
||||
font-weight: 300;
|
||||
font-size: 1.6rem;
|
||||
color: #333;
|
||||
margin-top: inherit;
|
||||
margin-bottom: 1rem;
|
||||
line-height: 1.25;
|
||||
|
||||
}
|
||||
|
||||
h3, h4, h5, h6, h7, h8 {
|
||||
border-top: 1px solid black;
|
||||
}
|
||||
|
||||
|
||||
|
||||
h2 { /* per-page main title */
|
||||
font-family: 'Cooper-Hewitt';
|
||||
margin-top: 4rem;
|
||||
font-size: 2.3rem;
|
||||
font-weight: bold;
|
||||
line-height: 1.2;
|
||||
width: 90%;
|
||||
/* a little nudge to make text visually lower than 4rem rule in left margin */
|
||||
position: relative;
|
||||
top: 6px;
|
||||
}
|
||||
|
||||
h3, h4, h5, h6, h7, h8 {
|
||||
margin-top: 2em;
|
||||
padding-top: 0.1em;
|
||||
margin-bottom: 0.75em;
|
||||
}
|
||||
|
||||
/* ---------------------------------------- */
|
||||
/* Main */
|
||||
|
||||
body {
|
||||
color: black;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.maincolumn {
|
||||
width: auto;
|
||||
margin-top: 4rem;
|
||||
margin-left: 17rem;
|
||||
margin-right: 2rem;
|
||||
margin-bottom: 10rem; /* to avoid fixed bottom nav bar */
|
||||
max-width: 700px;
|
||||
min-width: 370px; /* below this size, code samples don't fit */
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: inherit;
|
||||
}
|
||||
|
||||
a, .toclink, .toptoclink, .tocviewlink, .tocviewselflink, .tocviewtoggle, .plainlink,
|
||||
.techinside, .techoutside:hover, .techinside:hover {
|
||||
color: #07A;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
|
||||
/* ---------------------------------------- */
|
||||
/* Navigation */
|
||||
|
||||
.navsettop, .navsetbottom {
|
||||
left: 0;
|
||||
width: 15rem;
|
||||
height: 6rem;
|
||||
font-family: 'Fira', sans-serif;
|
||||
font-size: 0.9rem;
|
||||
border-bottom: 0px solid hsl(216, 15%, 70%);
|
||||
background-color: inherit;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.navsettop {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
margin-bottom: 0;
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.navsettop a, .navsetbottom a {
|
||||
color: black;
|
||||
}
|
||||
|
||||
.navsettop a:hover, .navsetbottom a:hover {
|
||||
background: hsl(216, 78%, 95%);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.navleft, .navright {
|
||||
position: static;
|
||||
float: none;
|
||||
margin: 0;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
|
||||
.navleft a {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.navright a {
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.navleft a, .navright a, .navright span {
|
||||
display: inline-block;
|
||||
padding: 0.5rem;
|
||||
min-width: 1rem;
|
||||
}
|
||||
|
||||
|
||||
.navright {
|
||||
height: 2rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
|
||||
.navsetbottom {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.nonavigation {
|
||||
color: #889;
|
||||
}
|
||||
|
||||
.searchform {
|
||||
display: block;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border-bottom: 1px solid #eee;
|
||||
height: 4rem;
|
||||
}
|
||||
|
||||
.nosearchform {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 4rem;
|
||||
}
|
||||
|
||||
.searchbox {
|
||||
font-size: 0.9rem;
|
||||
width: 12rem;
|
||||
margin: 1rem;
|
||||
padding: 0.25rem 0.4rem ;
|
||||
vertical-align: middle;
|
||||
background-color: white;
|
||||
font-family: 'Fira-Mono', monospace;
|
||||
}
|
||||
|
||||
|
||||
#search_box {
|
||||
font-family: 'Fira-Mono', monospace;
|
||||
font-size: 1rem;
|
||||
padding: 0.25rem 0.3rem ;
|
||||
}
|
||||
|
||||
/* Default to local view. Global will specialize */
|
||||
.plt_global_only { display: none; }
|
||||
.plt_local_only { display: block; }
|
||||
|
||||
/* ---------------------------------------- */
|
||||
/* Version */
|
||||
|
||||
.versionbox {
|
||||
position: absolute;
|
||||
float: none;
|
||||
top: 0.25rem;
|
||||
left: 17rem;
|
||||
z-index: 11000;
|
||||
height: 2em;
|
||||
font-size: 70%;
|
||||
font-weight: lighter;
|
||||
width: inherit;
|
||||
margin: 0;
|
||||
}
|
||||
.version, .versionNoNav {
|
||||
font-size: inherit;
|
||||
}
|
||||
.version:before, .versionNoNav:before {
|
||||
content: "v.";
|
||||
}
|
||||
|
||||
|
||||
/* ---------------------------------------- */
|
||||
/* Margin notes */
|
||||
|
||||
/* cancel scribble.css styles: */
|
||||
.refpara, .refelem {
|
||||
position: static;
|
||||
float: none;
|
||||
height: auto;
|
||||
width: auto;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.refcolumn {
|
||||
position: static;
|
||||
display: block;
|
||||
width: auto;
|
||||
font-size: inherit;
|
||||
margin: 2rem;
|
||||
margin-left: 2rem;
|
||||
padding: 0.5em;
|
||||
padding-left: 0.75em;
|
||||
padding-right: 1em;
|
||||
background: hsl(60, 29%, 94%);
|
||||
border: 1px solid #ccb;
|
||||
border-left: 0.4rem solid #ccb;
|
||||
}
|
||||
|
||||
|
||||
/* slightly different handling for margin-note* on narrow screens */
|
||||
@media all and (max-width:1340px) {
|
||||
span.refcolumn {
|
||||
float: right;
|
||||
width: 50%;
|
||||
margin-left: 1rem;
|
||||
margin-bottom: 0.8rem;
|
||||
margin-top: 1.2rem;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.refcontent, .refcontent p {
|
||||
line-height: 1.5;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.refcontent p + p {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.refcontent a {
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.refpara, .refparaleft {
|
||||
top: -1em;
|
||||
}
|
||||
|
||||
|
||||
@media all and (max-width:600px) {
|
||||
.refcolumn {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@media all and (min-width:1340px) {
|
||||
.refcolumn {
|
||||
margin: 0 -22.5rem 1rem 0;
|
||||
float: right;
|
||||
clear: right;
|
||||
width: 18rem;
|
||||
}
|
||||
}
|
||||
|
||||
.refcontent {
|
||||
font-family: 'Fira', sans-serif;
|
||||
font-size: 1rem;
|
||||
line-height: 1.6;
|
||||
margin: 0 0 0 0;
|
||||
}
|
||||
|
||||
|
||||
.refparaleft, .refelemleft {
|
||||
position: relative;
|
||||
float: left;
|
||||
right: 2em;
|
||||
height: 0em;
|
||||
width: 13em;
|
||||
margin: 0em 0em 0em -13em;
|
||||
}
|
||||
|
||||
.refcolumnleft {
|
||||
background-color: hsl(60, 29%, 94%);
|
||||
display: block;
|
||||
position: relative;
|
||||
width: 13em;
|
||||
font-size: 85%;
|
||||
border: 0.5em solid hsl(60, 29%, 94%);
|
||||
margin: 0 0 0 0;
|
||||
}
|
||||
|
||||
|
||||
/* ---------------------------------------- */
|
||||
/* Table of contents, left margin */
|
||||
|
||||
.tocset {
|
||||
position: absolute;
|
||||
float: none;
|
||||
left: 0;
|
||||
top: 0rem;
|
||||
width: 14rem;
|
||||
padding: 7rem 0.5rem 0.5rem 0.5rem;
|
||||
background-color: hsl(216, 15%, 70%);
|
||||
margin: 0;
|
||||
|
||||
}
|
||||
|
||||
.tocset td {
|
||||
vertical-align: text-top;
|
||||
padding-bottom: 0.4rem;
|
||||
padding-left: 0.2rem;
|
||||
line-height: 1.1;
|
||||
font-family: 'Fira', sans-serif;
|
||||
}
|
||||
|
||||
.tocset td a {
|
||||
color: black;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
|
||||
.tocview {
|
||||
text-align: left;
|
||||
background-color: inherit;
|
||||
}
|
||||
|
||||
|
||||
.tocview td, .tocsub td {
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
|
||||
.tocview table, .tocsub table {
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
.tocset td a.tocviewselflink {
|
||||
font-weight: lighter;
|
||||
font-size: 110%; /* monospaced styles below don't need to enlarge */
|
||||
color: white;
|
||||
}
|
||||
|
||||
.tocviewselflink {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.tocsub {
|
||||
text-align: left;
|
||||
margin-top: 0.5em;
|
||||
background-color: inherit;
|
||||
}
|
||||
|
||||
.tocviewlist, .tocsublist {
|
||||
margin-left: 0.2em;
|
||||
margin-right: 0.2em;
|
||||
padding-top: 0.2em;
|
||||
padding-bottom: 0.2em;
|
||||
}
|
||||
.tocviewlist table {
|
||||
font-size: 82%;
|
||||
}
|
||||
|
||||
.tocviewlisttopspace {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.tocviewsublist, .tocviewsublistonly, .tocviewsublisttop, .tocviewsublistbottom {
|
||||
margin-left: 0.4em;
|
||||
border-left: 1px solid #99a;
|
||||
padding-left: 0.8em;
|
||||
}
|
||||
.tocviewsublist {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
.tocviewsublist table,
|
||||
.tocviewsublistonly table,
|
||||
.tocviewsublisttop table,
|
||||
.tocviewsublistbottom table,
|
||||
table.tocsublist {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.tocviewsublist td,
|
||||
.tocviewsublistbottom td,
|
||||
.tocviewsublisttop td,
|
||||
.tocsub td,
|
||||
.tocviewsublistonly td {
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
/* shrink the monospaced text (`stt`) within nav */
|
||||
.tocviewsublist td .stt,
|
||||
.tocviewsublistbottom td .stt,
|
||||
.tocviewsublisttop td .stt,
|
||||
.tocsub td .stt,
|
||||
.tocviewsublistonly td .stt {
|
||||
font-size: 95%;
|
||||
}
|
||||
|
||||
|
||||
.tocviewtoggle {
|
||||
font-size: 75%; /* looks better, and avoids bounce when toggling sub-sections due to font alignments */
|
||||
}
|
||||
|
||||
.tocsublist td {
|
||||
padding-left: 0.5rem;
|
||||
padding-top: 0.25rem;
|
||||
text-indent: 0;
|
||||
}
|
||||
|
||||
.tocsublinknumber {
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
.tocsublink {
|
||||
font-size: 82%;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.tocsubseclink {
|
||||
font-size: 100%;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.tocsubnonseclink {
|
||||
font-size: 82%;
|
||||
text-decoration: none;
|
||||
margin-left: 1rem;
|
||||
padding-left: 0;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/* the label "on this page" */
|
||||
.tocsubtitle {
|
||||
display: block;
|
||||
font-size: 62%;
|
||||
font-family: 'Fira', sans-serif;
|
||||
font-weight: bolder;
|
||||
font-style: normal;
|
||||
letter-spacing: 2px;
|
||||
text-transform: uppercase;
|
||||
margin: 0.5em;
|
||||
}
|
||||
|
||||
.toptoclink {
|
||||
font-weight: bold;
|
||||
font-size: 110%;
|
||||
margin-bottom: 0.5rem;
|
||||
margin-top: 1.5rem;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.toclink {
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
/* ---------------------------------------- */
|
||||
/* Some inline styles */
|
||||
|
||||
.indexlink {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
pre {
|
||||
margin-left: 2em;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin-left: 2em;
|
||||
margin-right: 2em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.SCodeFlow {
|
||||
border-left: 1px dotted black;
|
||||
padding-left: 1em;
|
||||
padding-right: 1em;
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1em;
|
||||
margin-left: 0em;
|
||||
margin-right: 2em;
|
||||
white-space: nowrap;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.SCodeFlow img {
|
||||
margin-top: 0.5em;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
/* put a little air between lines of code sample */
|
||||
/* Fira Mono appears taller than Source Code Pro */
|
||||
.SCodeFlow td {
|
||||
padding-bottom: 1px;
|
||||
}
|
||||
|
||||
.boxed {
|
||||
margin: 0;
|
||||
margin-top: 2em;
|
||||
padding: 0.25em;
|
||||
padding-top: 0.3em;
|
||||
padding-bottom: 0.4em;
|
||||
background: #f3f3f3;
|
||||
box-sizing:border-box;
|
||||
border-top: 1px solid #99b;
|
||||
background: hsl(216, 78%, 95%);
|
||||
background: -moz-linear-gradient(to bottom left, hsl(0, 0%, 99%) 0%, hsl(216, 62%, 95%) 100%);
|
||||
background: -webkit-linear-gradient(to bottom left, hsl(0, 0%, 99%) 0%, hsl(216, 62%, 95%) 100%);
|
||||
background: -o-linear-gradient(to bottom left, hsl(0, 0%, 99%) 0%, hsl(216, 62%, 95%) 100%);
|
||||
background: -ms-linear-gradient(to bottom left, hsl(0, 0%, 99%) 0%, hsl(216, 62%, 95%) 100%);
|
||||
background: linear-gradient(to bottom left, hsl(0, 0%, 99%) 0%, hsl(216, 62%, 95%) 100%);
|
||||
}
|
||||
|
||||
blockquote > blockquote.SVInsetFlow {
|
||||
/* resolves issue in e.g. /reference/notation.html */
|
||||
margin-top: 0em;
|
||||
}
|
||||
|
||||
.leftindent .SVInsetFlow { /* see e.g. section 4.5 of Racket Guide */
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.SVInsetFlow a, .SCodeFlow a {
|
||||
color: #07A;
|
||||
}
|
||||
|
||||
.SubFlow {
|
||||
display: block;
|
||||
margin: 0em;
|
||||
}
|
||||
|
||||
.boxed {
|
||||
width: 100%;
|
||||
background-color: inherit;
|
||||
}
|
||||
|
||||
.techoutside { text-decoration: none; }
|
||||
|
||||
.SAuthorListBox {
|
||||
position: static;
|
||||
float: none;
|
||||
font-family: 'Fira', sans-serif;
|
||||
font-weight: 300;
|
||||
font-size: 110%;
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 2rem;
|
||||
width: 30rem;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.author > a { /* email links within author block */
|
||||
font-weight: inherit;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.SAuthorList {
|
||||
font-size: 82%;
|
||||
}
|
||||
.SAuthorList:before {
|
||||
content: "by ";
|
||||
}
|
||||
.author {
|
||||
display: inline;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* phone + tablet styles */
|
||||
|
||||
@media all and (max-width:720px){
|
||||
|
||||
|
||||
@media all and (max-width:720px){
|
||||
|
||||
@media all {html {font-size: 15px;}}
|
||||
@media all and (max-width:700px){html {font-size: 14px;}}
|
||||
@media all and (max-width:630px){html {font-size: 13px;}}
|
||||
@media all and (max-width:610px){html {font-size: 12px;}}
|
||||
@media all and (max-width:550px){html {font-size: 11px;}}
|
||||
@media all and (max-width:520px){html {font-size: 10px;}}
|
||||
|
||||
.navsettop, .navsetbottom {
|
||||
display: block;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 4rem;
|
||||
border: 0;
|
||||
background-color: hsl(216, 15%, 70%);
|
||||
}
|
||||
|
||||
.searchform {
|
||||
display: inline;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.navright {
|
||||
position: absolute;
|
||||
right: 1.5rem;
|
||||
margin-top: 1rem;
|
||||
border: 0px solid red;
|
||||
}
|
||||
|
||||
.navsetbottom {
|
||||
display: block;
|
||||
margin-top: 8rem;
|
||||
}
|
||||
|
||||
.tocset {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tocset table, .tocset tbody, .tocset tr, .tocset td {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.tocview {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tocsub .tocsubtitle {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.versionbox {
|
||||
top: 4.5rem;
|
||||
left: 1rem; /* same distance as main-column */
|
||||
z-index: 11000;
|
||||
height: 2em;
|
||||
font-size: 70%;
|
||||
font-weight: lighter;
|
||||
}
|
||||
|
||||
|
||||
.maincolumn {
|
||||
margin-left: 1em;
|
||||
margin-top: 7rem;
|
||||
margin-bottom: 0rem;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* print styles : hide the navigation elements */
|
||||
@media print {
|
||||
.tocset,
|
||||
.navsettop,
|
||||
.navsetbottom { display: none; }
|
||||
.maincolumn {
|
||||
width: auto;
|
||||
margin-right: 13em;
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
@ -0,0 +1,249 @@
|
||||
|
||||
/* See the beginning of "scribble.css". */
|
||||
|
||||
/* Monospace: */
|
||||
.RktIn, .RktRdr, .RktPn, .RktMeta,
|
||||
.RktMod, .RktKw, .RktVar, .RktSym,
|
||||
.RktRes, .RktOut, .RktCmt, .RktVal,
|
||||
.RktBlk {
|
||||
font-family: monospace;
|
||||
white-space: inherit;
|
||||
}
|
||||
|
||||
/* Serif: */
|
||||
.inheritedlbl {
|
||||
font-family: serif;
|
||||
}
|
||||
|
||||
/* Sans-serif: */
|
||||
.RBackgroundLabelInner {
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
/* ---------------------------------------- */
|
||||
/* Inherited methods, left margin */
|
||||
|
||||
.inherited {
|
||||
width: 100%;
|
||||
margin-top: 0.5em;
|
||||
text-align: left;
|
||||
background-color: #ECF5F5;
|
||||
}
|
||||
|
||||
.inherited td {
|
||||
font-size: 82%;
|
||||
padding-left: 1em;
|
||||
text-indent: -0.8em;
|
||||
padding-right: 0.2em;
|
||||
}
|
||||
|
||||
.inheritedlbl {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* ---------------------------------------- */
|
||||
/* Racket text styles */
|
||||
|
||||
.RktIn {
|
||||
color: #cc6633;
|
||||
background-color: #eeeeee;
|
||||
}
|
||||
|
||||
.RktInBG {
|
||||
background-color: #eeeeee;
|
||||
}
|
||||
|
||||
.RktRdr {
|
||||
}
|
||||
|
||||
.RktPn {
|
||||
color: #843c24;
|
||||
}
|
||||
|
||||
.RktMeta {
|
||||
color: black;
|
||||
}
|
||||
|
||||
.RktMod {
|
||||
color: black;
|
||||
}
|
||||
|
||||
.RktOpt {
|
||||
color: black;
|
||||
}
|
||||
|
||||
.RktKw {
|
||||
color: black;
|
||||
}
|
||||
|
||||
.RktErr {
|
||||
color: red;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.RktVar {
|
||||
color: #262680;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.RktSym {
|
||||
color: #262680;
|
||||
}
|
||||
|
||||
.RktSymDef { /* used with RktSym at def site */
|
||||
}
|
||||
|
||||
.RktValLink {
|
||||
text-decoration: none;
|
||||
color: blue;
|
||||
}
|
||||
|
||||
.RktValDef { /* used with RktValLink at def site */
|
||||
}
|
||||
|
||||
.RktModLink {
|
||||
text-decoration: none;
|
||||
color: blue;
|
||||
}
|
||||
|
||||
.RktStxLink {
|
||||
text-decoration: none;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.RktStxDef { /* used with RktStxLink at def site */
|
||||
}
|
||||
|
||||
.RktRes {
|
||||
color: #0000af;
|
||||
}
|
||||
|
||||
.RktOut {
|
||||
color: #960096;
|
||||
}
|
||||
|
||||
.RktCmt {
|
||||
color: #c2741f;
|
||||
}
|
||||
|
||||
.RktVal {
|
||||
color: #228b22;
|
||||
}
|
||||
|
||||
/* ---------------------------------------- */
|
||||
/* Some inline styles */
|
||||
|
||||
.together {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.prototype, .argcontract, .RBoxed {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.prototype td {
|
||||
vertical-align: text-top;
|
||||
}
|
||||
|
||||
.RktBlk {
|
||||
white-space: inherit;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.RktBlk tr {
|
||||
white-space: inherit;
|
||||
}
|
||||
|
||||
.RktBlk td {
|
||||
vertical-align: baseline;
|
||||
white-space: inherit;
|
||||
}
|
||||
|
||||
.argcontract td {
|
||||
vertical-align: text-top;
|
||||
}
|
||||
|
||||
.highlighted {
|
||||
background-color: #ddddff;
|
||||
}
|
||||
|
||||
.defmodule {
|
||||
width: 100%;
|
||||
background-color: #F5F5DC;
|
||||
}
|
||||
|
||||
.specgrammar {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.RBibliography td {
|
||||
vertical-align: text-top;
|
||||
}
|
||||
|
||||
.leftindent {
|
||||
margin-left: 1em;
|
||||
margin-right: 0em;
|
||||
}
|
||||
|
||||
.insetpara {
|
||||
margin-left: 1em;
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
.Rfilebox {
|
||||
}
|
||||
|
||||
.Rfiletitle {
|
||||
text-align: right;
|
||||
margin: 0em 0em 0em 0em;
|
||||
}
|
||||
|
||||
.Rfilename {
|
||||
border-top: 1px solid #6C8585;
|
||||
border-right: 1px solid #6C8585;
|
||||
padding-left: 0.5em;
|
||||
padding-right: 0.5em;
|
||||
background-color: #ECF5F5;
|
||||
}
|
||||
|
||||
.Rfilecontent {
|
||||
margin: 0em 0em 0em 0em;
|
||||
}
|
||||
|
||||
.RpackageSpec {
|
||||
padding-right: 0.5em;
|
||||
}
|
||||
|
||||
/* ---------------------------------------- */
|
||||
/* For background labels */
|
||||
|
||||
.RBackgroundLabel {
|
||||
float: right;
|
||||
width: 0px;
|
||||
height: 0px;
|
||||
}
|
||||
|
||||
.RBackgroundLabelInner {
|
||||
position: relative;
|
||||
width: 25em;
|
||||
left: -25.5em;
|
||||
top: 0px;
|
||||
text-align: right;
|
||||
color: white;
|
||||
z-index: 0;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.RForeground {
|
||||
position: relative;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* ---------------------------------------- */
|
||||
/* History */
|
||||
|
||||
.SHistory {
|
||||
font-size: 82%;
|
||||
}
|
@ -0,0 +1,170 @@
|
||||
// Common functionality for PLT documentation pages
|
||||
|
||||
// Page Parameters ------------------------------------------------------------
|
||||
|
||||
var page_query_string = location.search.substring(1);
|
||||
|
||||
var page_args =
|
||||
((function(){
|
||||
if (!page_query_string) return [];
|
||||
var args = page_query_string.split(/[&;]/);
|
||||
for (var i=0; i<args.length; i++) {
|
||||
var a = args[i];
|
||||
var p = a.indexOf('=');
|
||||
if (p >= 0) args[i] = [a.substring(0,p), a.substring(p+1)];
|
||||
else args[i] = [a, false];
|
||||
}
|
||||
return args;
|
||||
})());
|
||||
|
||||
function GetPageArg(key, def) {
|
||||
for (var i=0; i<page_args.length; i++)
|
||||
if (page_args[i][0] == key) return decodeURIComponent(page_args[i][1]);
|
||||
return def;
|
||||
}
|
||||
|
||||
function MergePageArgsIntoLink(a) {
|
||||
if (page_args.length == 0 ||
|
||||
(!a.attributes["data-pltdoc"]) || (a.attributes["data-pltdoc"].value == ""))
|
||||
return;
|
||||
a.href = MergePageArgsIntoUrl(a.href);
|
||||
}
|
||||
|
||||
function MergePageArgsIntoUrl(href) {
|
||||
var mtch = href.match(/^([^?#]*)(?:\?([^#]*))?(#.*)?$/);
|
||||
if (mtch == undefined) { // I think this never happens
|
||||
return "?" + page_query_string;
|
||||
}
|
||||
if (!mtch[2]) {
|
||||
return mtch[1] + "?" + page_query_string + (mtch[3] || "");
|
||||
}
|
||||
// need to merge here, precedence to arguments that exist in `a'
|
||||
var i, j;
|
||||
var prefix = mtch[1], str = mtch[2] || "", suffix = mtch[3] || "";
|
||||
var args = str.split(/[&;]/);
|
||||
for (i=0; i<args.length; i++) {
|
||||
j = args[i].indexOf('=');
|
||||
if (j) args[i] = args[i].substring(0,j);
|
||||
}
|
||||
var additions = "";
|
||||
for (i=0; i<page_args.length; i++) {
|
||||
var exists = false;
|
||||
for (j=0; j<args.length; j++)
|
||||
if (args[j] == page_args[i][0]) { exists = true; break; }
|
||||
if (!exists) str += "&" + page_args[i][0] + "=" + page_args[i][1];
|
||||
}
|
||||
return prefix + "?" + str + suffix;
|
||||
}
|
||||
|
||||
// Cookies --------------------------------------------------------------------
|
||||
|
||||
// Actually, try localStorage (a la HTML 5), first.
|
||||
|
||||
function GetCookie(key, def) {
|
||||
try {
|
||||
var v = localStorage[key];
|
||||
if (!v) v = def;
|
||||
return v;
|
||||
} catch (e) {
|
||||
var i, cookiestrs;
|
||||
try {
|
||||
if (document.cookie.length <= 0) return def;
|
||||
cookiestrs = document.cookie.split(/; */);
|
||||
} catch (e) { return def; }
|
||||
for (i = 0; i < cookiestrs.length; i++) {
|
||||
var cur = cookiestrs[i];
|
||||
var eql = cur.indexOf('=');
|
||||
if (eql >= 0 && cur.substring(0,eql) == key)
|
||||
return unescape(cur.substring(eql+1));
|
||||
}
|
||||
return def;
|
||||
}
|
||||
}
|
||||
|
||||
function SetCookie(key, val) {
|
||||
try {
|
||||
localStorage[key] = val;
|
||||
} catch(e) {
|
||||
var d = new Date();
|
||||
d.setTime(d.getTime()+(365*24*60*60*1000));
|
||||
try {
|
||||
document.cookie =
|
||||
key + "=" + escape(val) + "; expires="+ d.toGMTString() + "; path=/";
|
||||
} catch (e) {}
|
||||
}
|
||||
}
|
||||
|
||||
// note that this always stores a directory name, ending with a "/"
|
||||
function SetPLTRoot(ver, relative) {
|
||||
var root = location.protocol + "//" + location.host
|
||||
+ NormalizePath(location.pathname.replace(/[^\/]*$/, relative));
|
||||
SetCookie("PLT_Root."+ver, root);
|
||||
}
|
||||
|
||||
// adding index.html works because of the above
|
||||
function GotoPLTRoot(ver, relative) {
|
||||
var u = GetCookie("PLT_Root."+ver, null);
|
||||
if (u == null) return true; // no cookie: use plain up link
|
||||
// the relative path is optional, default goes to the toplevel start page
|
||||
if (!relative) relative = "index.html";
|
||||
location = u + relative;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Utilities ------------------------------------------------------------------
|
||||
|
||||
var normalize_rxs = [/\/\/+/g, /\/\.(\/|$)/, /\/[^\/]*\/\.\.(\/|$)/];
|
||||
function NormalizePath(path) {
|
||||
var tmp, i;
|
||||
for (i = 0; i < normalize_rxs.length; i++)
|
||||
while ((tmp = path.replace(normalize_rxs[i], "/")) != path) path = tmp;
|
||||
return path;
|
||||
}
|
||||
|
||||
// `noscript' is problematic in some browsers (always renders as a
|
||||
// block), use this hack instead (does not always work!)
|
||||
// document.write("<style>mynoscript { display:none; }</style>");
|
||||
|
||||
// Interactions ---------------------------------------------------------------
|
||||
|
||||
function DoSearchKey(event, field, ver, top_path) {
|
||||
var val = field.value;
|
||||
if (event && event.keyCode == 13) {
|
||||
var u = GetCookie("PLT_Root."+ver, null);
|
||||
if (u == null) u = top_path; // default: go to the top path
|
||||
u += "search/index.html?q=" + encodeURIComponent(val);
|
||||
u = MergePageArgsIntoUrl(u);
|
||||
location = u;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function TocviewToggle(glyph, id) {
|
||||
var s = document.getElementById(id).style;
|
||||
var expand = s.display == "none";
|
||||
s.display = expand ? "block" : "none";
|
||||
glyph.innerHTML = expand ? "▼" : "►";
|
||||
}
|
||||
|
||||
// Page Init ------------------------------------------------------------------
|
||||
|
||||
// Note: could make a function that inspects and uses window.onload to chain to
|
||||
// a previous one, but this file needs to be required first anyway, since it
|
||||
// contains utilities for all other files.
|
||||
var on_load_funcs = [];
|
||||
function AddOnLoad(fun) { on_load_funcs.push(fun); }
|
||||
window.onload = function() {
|
||||
for (var i=0; i<on_load_funcs.length; i++) on_load_funcs[i]();
|
||||
};
|
||||
|
||||
AddOnLoad(function(){
|
||||
var links = document.getElementsByTagName("a");
|
||||
for (var i=0; i<links.length; i++) MergePageArgsIntoLink(links[i]);
|
||||
var label = GetPageArg("ctxtname",false);
|
||||
if (!label) return;
|
||||
var indicator = document.getElementById("contextindicator");
|
||||
if (!indicator) return;
|
||||
indicator.innerHTML = label;
|
||||
indicator.style.display = "block";
|
||||
});
|
@ -0,0 +1,485 @@
|
||||
|
||||
/* This file is used by default by all Scribble documents.
|
||||
See also "manual.css", which is added by default by the
|
||||
`scribble/manual` language. */
|
||||
|
||||
/* CSS seems backward: List all the classes for which we want a
|
||||
particular font, so that the font can be changed in one place. (It
|
||||
would be nicer to reference a font definition from all the places
|
||||
that we want it.)
|
||||
|
||||
As you read the rest of the file, remember to double-check here to
|
||||
see if any font is set. */
|
||||
|
||||
/* Monospace: */
|
||||
.maincolumn, .refpara, .refelem, .tocset, .stt, .hspace, .refparaleft, .refelemleft {
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
/* Serif: */
|
||||
.main, .refcontent, .tocview, .tocsub, .sroman, i {
|
||||
font-family: serif;
|
||||
}
|
||||
|
||||
/* Sans-serif: */
|
||||
.version, .versionNoNav, .ssansserif {
|
||||
font-family: sans-serif;
|
||||
}
|
||||
.ssansserif {
|
||||
font-size: 80%;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* ---------------------------------------- */
|
||||
|
||||
p, .SIntrapara {
|
||||
display: block;
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
h2 { /* per-page main title */
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
h3, h4, h5, h6, h7, h8 {
|
||||
margin-top: 1.75em;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.SSubSubSubSection {
|
||||
font-weight: bold;
|
||||
font-size: 0.83em; /* should match h5; from HTML 4 reference */
|
||||
}
|
||||
|
||||
/* Needed for browsers like Opera, and eventually for HTML 4 conformance.
|
||||
This means that multiple paragraphs in a table element do not have a space
|
||||
between them. */
|
||||
table p {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/* ---------------------------------------- */
|
||||
/* Main */
|
||||
|
||||
body {
|
||||
color: black;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
table td {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.maincolumn {
|
||||
width: 43em;
|
||||
margin-right: -40em;
|
||||
margin-left: 15em;
|
||||
}
|
||||
|
||||
.main {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
/* ---------------------------------------- */
|
||||
/* Navigation */
|
||||
|
||||
.navsettop, .navsetbottom {
|
||||
background-color: #f0f0e0;
|
||||
padding: 0.25em 0 0.25em 0;
|
||||
}
|
||||
|
||||
.navsettop {
|
||||
margin-bottom: 1.5em;
|
||||
border-bottom: 2px solid #e0e0c0;
|
||||
}
|
||||
|
||||
.navsetbottom {
|
||||
margin-top: 2em;
|
||||
border-top: 2px solid #e0e0c0;
|
||||
}
|
||||
|
||||
.navleft {
|
||||
margin-left: 1ex;
|
||||
position: relative;
|
||||
float: left;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.navright {
|
||||
margin-right: 1ex;
|
||||
position: relative;
|
||||
float: right;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.nonavigation {
|
||||
color: #e0e0e0;
|
||||
}
|
||||
|
||||
.searchform {
|
||||
display: inline;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.nosearchform {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.searchbox {
|
||||
width: 16em;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
background-color: #eee;
|
||||
border: 1px solid #ddd;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
#contextindicator {
|
||||
position: fixed;
|
||||
background-color: #c6f;
|
||||
color: #000;
|
||||
font-family: monospace;
|
||||
font-weight: bold;
|
||||
padding: 2px 10px;
|
||||
display: none;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
/* ---------------------------------------- */
|
||||
/* Version */
|
||||
|
||||
.versionbox {
|
||||
position: relative;
|
||||
float: right;
|
||||
left: 2em;
|
||||
height: 0em;
|
||||
width: 13em;
|
||||
margin: 0em -13em 0em 0em;
|
||||
}
|
||||
.version {
|
||||
font-size: small;
|
||||
}
|
||||
.versionNoNav {
|
||||
font-size: xx-small; /* avoid overlap with author */
|
||||
}
|
||||
|
||||
.version:before, .versionNoNav:before {
|
||||
content: "Version ";
|
||||
}
|
||||
|
||||
/* ---------------------------------------- */
|
||||
/* Margin notes */
|
||||
|
||||
.refpara, .refelem {
|
||||
position: relative;
|
||||
float: right;
|
||||
left: 2em;
|
||||
height: 0em;
|
||||
width: 13em;
|
||||
margin: 0em -13em 0em 0em;
|
||||
}
|
||||
|
||||
.refpara, .refparaleft {
|
||||
top: -1em;
|
||||
}
|
||||
|
||||
.refcolumn {
|
||||
background-color: #F5F5DC;
|
||||
display: block;
|
||||
position: relative;
|
||||
width: 13em;
|
||||
font-size: 85%;
|
||||
border: 0.5em solid #F5F5DC;
|
||||
margin: 0 0 0 0;
|
||||
white-space: normal; /* in case margin note is inside code sample */
|
||||
}
|
||||
|
||||
.refcontent {
|
||||
margin: 0 0 0 0;
|
||||
}
|
||||
|
||||
.refcontent p {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.refparaleft, .refelemleft {
|
||||
position: relative;
|
||||
float: left;
|
||||
right: 2em;
|
||||
height: 0em;
|
||||
width: 13em;
|
||||
margin: 0em 0em 0em -13em;
|
||||
}
|
||||
|
||||
.refcolumnleft {
|
||||
background-color: #F5F5DC;
|
||||
display: block;
|
||||
position: relative;
|
||||
width: 13em;
|
||||
font-size: 85%;
|
||||
border: 0.5em solid #F5F5DC;
|
||||
margin: 0 0 0 0;
|
||||
}
|
||||
|
||||
|
||||
/* ---------------------------------------- */
|
||||
/* Table of contents, inline */
|
||||
|
||||
.toclink {
|
||||
text-decoration: none;
|
||||
color: blue;
|
||||
font-size: 85%;
|
||||
}
|
||||
|
||||
.toptoclink {
|
||||
text-decoration: none;
|
||||
color: blue;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* ---------------------------------------- */
|
||||
/* Table of contents, left margin */
|
||||
|
||||
.tocset {
|
||||
position: relative;
|
||||
float: left;
|
||||
width: 12.5em;
|
||||
margin-right: 2em;
|
||||
}
|
||||
.tocset td {
|
||||
vertical-align: text-top;
|
||||
}
|
||||
|
||||
.tocview {
|
||||
text-align: left;
|
||||
background-color: #f0f0e0;
|
||||
}
|
||||
|
||||
.tocsub {
|
||||
text-align: left;
|
||||
margin-top: 0.5em;
|
||||
background-color: #f0f0e0;
|
||||
}
|
||||
|
||||
.tocviewlist, .tocsublist {
|
||||
margin-left: 0.2em;
|
||||
margin-right: 0.2em;
|
||||
padding-top: 0.2em;
|
||||
padding-bottom: 0.2em;
|
||||
}
|
||||
.tocviewlist table {
|
||||
font-size: 82%;
|
||||
}
|
||||
|
||||
.tocviewlisttopspace {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.tocviewsublist, .tocviewsublistonly, .tocviewsublisttop, .tocviewsublistbottom {
|
||||
margin-left: 0.4em;
|
||||
border-left: 1px solid #bbf;
|
||||
padding-left: 0.8em;
|
||||
}
|
||||
.tocviewsublist {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
.tocviewsublist table,
|
||||
.tocviewsublistonly table,
|
||||
.tocviewsublisttop table,
|
||||
.tocviewsublistbottom table {
|
||||
font-size: 75%;
|
||||
}
|
||||
|
||||
.tocviewtitle * {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.tocviewlink {
|
||||
text-decoration: none;
|
||||
color: blue;
|
||||
}
|
||||
|
||||
.tocviewselflink {
|
||||
text-decoration: underline;
|
||||
color: blue;
|
||||
}
|
||||
|
||||
.tocviewtoggle {
|
||||
text-decoration: none;
|
||||
color: blue;
|
||||
font-size: 75%; /* looks better, and avoids bounce when toggling sub-sections due to font alignments */
|
||||
}
|
||||
|
||||
.tocsublist td {
|
||||
padding-left: 1em;
|
||||
text-indent: -1em;
|
||||
}
|
||||
|
||||
.tocsublinknumber {
|
||||
font-size: 82%;
|
||||
}
|
||||
|
||||
.tocsublink {
|
||||
font-size: 82%;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.tocsubseclink {
|
||||
font-size: 82%;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.tocsubnonseclink {
|
||||
font-size: 82%;
|
||||
text-decoration: none;
|
||||
padding-left: 0.5em;
|
||||
}
|
||||
|
||||
.tocsubtitle {
|
||||
font-size: 82%;
|
||||
font-style: italic;
|
||||
margin: 0.2em;
|
||||
}
|
||||
|
||||
/* ---------------------------------------- */
|
||||
/* Some inline styles */
|
||||
|
||||
.indexlink {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.nobreak {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
pre { margin-left: 2em; }
|
||||
blockquote { margin-left: 2em; }
|
||||
|
||||
ol { list-style-type: decimal; }
|
||||
ol ol { list-style-type: lower-alpha; }
|
||||
ol ol ol { list-style-type: lower-roman; }
|
||||
ol ol ol ol { list-style-type: upper-alpha; }
|
||||
|
||||
.SCodeFlow {
|
||||
display: block;
|
||||
margin-left: 1em;
|
||||
margin-bottom: 0em;
|
||||
margin-right: 1em;
|
||||
margin-top: 0em;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.SVInsetFlow {
|
||||
display: block;
|
||||
margin-left: 0em;
|
||||
margin-bottom: 0em;
|
||||
margin-right: 0em;
|
||||
margin-top: 0em;
|
||||
}
|
||||
|
||||
.SubFlow {
|
||||
display: block;
|
||||
margin: 0em;
|
||||
}
|
||||
|
||||
.boxed {
|
||||
width: 100%;
|
||||
background-color: #E8E8FF;
|
||||
}
|
||||
|
||||
.hspace {
|
||||
}
|
||||
|
||||
.slant {
|
||||
font-style: oblique;
|
||||
}
|
||||
|
||||
.badlink {
|
||||
text-decoration: underline;
|
||||
color: red;
|
||||
}
|
||||
|
||||
.plainlink {
|
||||
text-decoration: none;
|
||||
color: blue;
|
||||
}
|
||||
|
||||
.techoutside { text-decoration: underline; color: #b0b0b0; }
|
||||
.techoutside:hover { text-decoration: underline; color: blue; }
|
||||
|
||||
/* .techinside:hover doesn't work with FF, .techinside:hover>
|
||||
.techinside doesn't work with IE, so use both (and IE doesn't
|
||||
work with inherit in the second one, so use blue directly) */
|
||||
.techinside { color: black; }
|
||||
.techinside:hover { color: blue; }
|
||||
.techoutside:hover>.techinside { color: inherit; }
|
||||
|
||||
.SCentered {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.imageleft {
|
||||
float: left;
|
||||
margin-right: 0.3em;
|
||||
}
|
||||
|
||||
.Smaller {
|
||||
font-size: 82%;
|
||||
}
|
||||
|
||||
.Larger {
|
||||
font-size: 122%;
|
||||
}
|
||||
|
||||
/* A hack, inserted to break some Scheme ids: */
|
||||
.mywbr {
|
||||
display: inline-block;
|
||||
height: 0;
|
||||
width: 0;
|
||||
font-size: 1px;
|
||||
}
|
||||
|
||||
.compact li p {
|
||||
margin: 0em;
|
||||
padding: 0em;
|
||||
}
|
||||
|
||||
.noborder img {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.SAuthorListBox {
|
||||
position: relative;
|
||||
float: right;
|
||||
left: 2em;
|
||||
top: -2.5em;
|
||||
height: 0em;
|
||||
width: 13em;
|
||||
margin: 0em -13em 0em 0em;
|
||||
}
|
||||
.SAuthorList {
|
||||
font-size: 82%;
|
||||
}
|
||||
.SAuthorList:before {
|
||||
content: "by ";
|
||||
}
|
||||
.author {
|
||||
display: inline;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* print styles : hide the navigation elements */
|
||||
@media print {
|
||||
.tocset,
|
||||
.navsettop,
|
||||
.navsetbottom { display: none; }
|
||||
.maincolumn {
|
||||
width: auto;
|
||||
margin-right: 13em;
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
@ -1 +0,0 @@
|
||||
../../../../../../../usr/local/lib/node_modules/pdfkit
|
Loading…
Reference in New Issue