; Copyright (c) 1993-2001 by Richard Kelsey and Jonathan Rees. See file COPYING. ; Exports: ; make-regexp ; regexp? ; regexp-match ; regexp-match? ; regexp-match-start ; regexp-match-end ; regexp-option ; The compiled version of the expression is produced when needed. (define-record-type regexp :regexp (really-make-regexp pattern compiled extended? ignore-case? submatches? newline?) regexp? (pattern regexp-pattern) ; immutable string (compiled real-regexp-compiled set-regexp-compiled!) ; #f or a c-record (extended? regexp-extended?) ; four flags (ignore-case? regexp-ignore-case?) (submatches? regexp-submatches?) (newline? regexp-newline?)) ; Drop the compiled version when resuming. We may be resuming on a different ; architecture, or version of the library, or whatever. (define-record-resumer :regexp (lambda (regexp) (set-regexp-compiled! regexp #f))) ; There are four options when making a regular expression. (define-enumerated-type regexp-option :regexp-option regexp-option? regexp-options regexp-option-name regexp-option-index (extended ignore-case submatches newline)) ; Loop down finding which options are present and checking for duplicates. ; This is not specific to regular expressions. ; ; It would be nice if this could handle values as well, as in ; (make-regexp "sldkjf" (regexp-option size 10)) (define (decode-boolean-options options all-options predicate indexer) (let ((map (make-vector (vector-length all-options) #f))) (let loop ((options options)) (if (null? options) (vector->list map) (let ((option (car options))) (if (predicate option) (let ((index (indexer option))) (if (vector-ref map index) 'duplicates (begin (vector-set! map index #t) (loop (cdr options))))) 'bad-value)))))) ; The only thing we do here is to decode the options and make sure that the ; pattern is immutable, as it won't be used until later. (define (make-regexp pattern . options) (let ((options (decode-boolean-options options regexp-options regexp-option? regexp-option-index))) (if (and (string? pattern) (pair? options)) (let* ((pattern (immutable-copy-string pattern)) (regexp (apply really-make-regexp pattern #f options))) (add-finalizer! regexp free-compiled-regexp) regexp) (apply call-error "invalid argument(s)" make-regexp pattern options)))) ; Free up the C-heap storage used for the compiled regexp. (define (free-compiled-regexp regexp) (let ((compiled (real-regexp-compiled regexp))) (if compiled (call-imported-binding posix-free-regexp compiled)))) ; We compile the pattern if that hasn't already been done, raising an error ; if anything goes wrong. (define (regexp-compiled regexp) (or (real-regexp-compiled regexp) (let ((compiled (call-imported-binding posix-compile-regexp (regexp-pattern regexp) (regexp-extended? regexp) (regexp-ignore-case? regexp) (regexp-submatches? regexp) (regexp-newline? regexp)))) (if (not (integer? compiled)) (begin (set-regexp-compiled! regexp compiled) compiled) (let ((message (call-imported-binding posix-regexp-error-message (regexp-pattern regexp) (regexp-extended? regexp) (regexp-ignore-case? regexp) (regexp-submatches? regexp) (regexp-newline? regexp)))) (error (if message (string-append "Posix regexp: " message) "inconsistent results from Posix regexp compiler") regexp)))))) ; Call the pattern matcher. We return #F if the match fails. On a successful ; match, we either return #T or a list of match records, depending on the value ; of SUBMATCHES?. (define (regexp-match regexp string submatches? starts-line? ends-line? . rest) (if (and (regexp? regexp) (string? string)) (let ((start (if (null? rest) 0 (car rest)))) (call-imported-binding posix-regexp-match (regexp-compiled regexp) string submatches? starts-line? ends-line? start)) (call-error "invalid argument" regexp-match regexp string starts-line? ends-line?))) ; These are made by the C code. The SUBMATCHES field is not used by us, ; but is used by the functional interface. (define-record-type match :match (make-match start end submatches) match? (start match-start) (end match-end) (submatches match-submatches)) (define-record-discloser :match (lambda (rem) (list 'match (match-start rem) (match-end rem)))) (define-exported-binding "posix-regexp-match-type" :match) ; The various C functions we use. (import-definition posix-compile-regexp) (import-definition posix-regexp-match) (import-definition posix-regexp-error-message) (import-definition posix-free-regexp)