diff --git a/lib/tcl/runtime.sx b/lib/tcl/runtime.sx index 6daf03d9..158e6b4b 100644 --- a/lib/tcl/runtime.sx +++ b/lib/tcl/runtime.sx @@ -2903,6 +2903,84 @@ (define tcl-cmd-tell (fn (interp args) (assoc interp :result "0"))) (define tcl-cmd-flush (fn (interp args) (assoc interp :result ""))) +(define + tcl-cmd-regexp + (fn + (interp args) + (define parse-flags + (fn (as nocase? all? inline?) + (if (= 0 (len as)) + {:nocase nocase? :all all? :inline inline? :rest as} + (cond + ((equal? (first as) "-nocase") (parse-flags (rest as) true all? inline?)) + ((equal? (first as) "-all") (parse-flags (rest as) nocase? true inline?)) + ((equal? (first as) "-inline") (parse-flags (rest as) nocase? all? true)) + (else {:nocase nocase? :all all? :inline inline? :rest as}))))) + (let ((pf (parse-flags args false false false))) + (let ((nocase (get pf :nocase)) + (all-mode (get pf :all)) + (inline-mode (get pf :inline)) + (ra (get pf :rest))) + (if (< (len ra) 2) + (error "regexp: wrong # args") + (let ((pattern (first ra)) + (str-val (nth ra 1)) + (var-args (if (> (len ra) 2) (rest (rest ra)) (list)))) + (let ((re (make-regexp pattern (if nocase "i" "")))) + (if all-mode + (assoc interp :result (str (len (regexp-match-all re str-val)))) + (if inline-mode + (assoc interp :result (join " " (map (fn (m) (get m :match)) (regexp-match-all re str-val)))) + (let ((m (regexp-match re str-val))) + (if (nil? m) + (assoc interp :result "0") + (let ((interp2 + (if (> (len var-args) 0) + (tcl-var-set interp (first var-args) (get m :match)) + interp))) + (let ((interp3 + (let loop ((vi 1) (gs (get m :groups)) (acc interp2)) + (if (or (= 0 (len gs)) (>= vi (len var-args))) acc + (loop (+ vi 1) (rest gs) + (tcl-var-set acc (nth var-args vi) (first gs))))))) + (assoc interp3 :result "1")))))))))))))) + +(define + tcl-cmd-regsub + (fn + (interp args) + (define parse-flags + (fn (as all? nocase?) + (if (= 0 (len as)) + {:all all? :nocase nocase? :rest as} + (cond + ((equal? (first as) "-all") (parse-flags (rest as) true nocase?)) + ((equal? (first as) "-nocase") (parse-flags (rest as) all? true)) + (else {:all all? :nocase nocase? :rest as}))))) + (let ((pf (parse-flags args false false))) + (let ((all-mode (get pf :all)) + (nocase (get pf :nocase)) + (ra (get pf :rest))) + (if (< (len ra) 3) + (error "regsub: wrong # args") + (let ((pattern (first ra)) + (str-val (nth ra 1)) + (replacement (nth ra 2)) + (var-name (if (> (len ra) 3) (nth ra 3) nil))) + (let ((re (make-regexp pattern (if nocase "i" "")))) + (let ((result + (if all-mode + (regexp-replace-all re str-val replacement) + (regexp-replace re str-val replacement)))) + (if (nil? var-name) + (assoc interp :result result) + (let ((count + (if all-mode + (len (regexp-match-all re str-val)) + (if (nil? (regexp-match re str-val)) 0 1)))) + (assoc (tcl-var-set interp var-name result) :result (str count)))))))))))) + + (define tcl-cmd-file @@ -3092,7 +3170,6 @@ ((i (tcl-register i "tell" tcl-cmd-tell))) (let ((i (tcl-register i "flush" tcl-cmd-flush))) - (tcl-register - i - "file" - tcl-cmd-file)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) + (let ((i (tcl-register i "file" tcl-cmd-file))) + (let ((i (tcl-register i "regexp" tcl-cmd-regexp))) + (tcl-register i "regsub" tcl-cmd-regsub))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))