When I set up an emacs process filter, I never know how much input the process will deliver me at one time. Therefore I generally buffer the input and process (say) a line at a time.
(defvar buffer "") (defun process-input (input) (setq buffer (concat input buffer)) (let ((count 0) (pos 0)) (while (string-match "^\\([^\n]+\\)\n" buffer pos) (message "Before: [%s] [%d]" (match-string 1 buffer) (match-end 1)) (process-line (match-string 1 buffer)) (message "After: [%s] [%d]" (match-string 1 buffer) (match-end 1)) ;; error handling in case of runaway loops (incf count) (when (> count 10) (error "Looped too many times!")) (setq pos (1+ (match-end 1)))) (when pos (setq buffer (substring buffer pos)))) (message "REMAINDER: [%s]" buffer))
Given a simple (process-line ...) we can see the results from a simple test.
(defun process-line (line) (message "[%s]" line)) (process-input "XXX (line 1)\n13.15 (line 2)\n")
Before: XXX (line 1) 12 [XXX (line 1)] After: XXX (line 1) 12 Before: 13.15 (line 2) 27 [13.15 (line 2)] After: 13.15 (line 2) 27 REMAINDER: []
An Infinite Loop
Now say I want to add some special handling for lines with a number in, what do you think happens?
(defun process-line (line) (when (string-match "\\([0-9]+\.[0-9]+\\)" line) (message "[%s]" line)))
Debugger entered--Lisp error: (error "Looped too many times!")
Before: [XXX (line 1)] [12]
After: [XXX (line 1)] [12]
Before: [13.15 (line 2)] [27]
[13.15 (line 2)]
After: [XXX (] [5]
Before: [13.15 (line 2)] [27]
[13.15 (line 2)]
After: [XXX (] [5]
...
The string match against the number has reset a hidden global variable used by (match-end ...) which has sent us into an infinite loop. Surprising action at a distance indeed!
Perl Regex Globals
Perl also uses global variables such as $1, $2, @- and @+ for its regular expressions, so could this cause a similar problem?
No. Fortunately, these globals are dynamically scoped so the appropriate values are maintained up the call stack.