;;; auto-edit-substitute.el --- Automatically edit files by substituting values into them.

;;; Copyright (C) 2001 Nix <nix@esperi.org.uk>.

;; Author: Nix <nix@esperi.org.uk>
;; Created: 2001-06-01
;; Keywords: lisp

;; This file is not part of Emacs.

;; This library is free software; you can redistribute it and/or modify it
;; under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2.1, or (at your option)
;; any later version.

;;; Commentary:

;; This file lets you do things like automatically edit web pages from hooks
;; and suchlike.

;;; Code:

(defun auto-edit-substitute (substitutions &optional buffer)
  "Automatically edit a BUFFER by applying SUBSTITUTIONS to it one by one.

The SUBSTITUTIONS are an alist of elements like (START END SUBSTITUTION), where
START and END are regexps matching tags delineating a region to which a
substitution is to be applied, and SUBSTITUTION is one of:

  A string -- the string is substituted for each region verbatim.
  A function -- the function is applied to each region with the
                current buffer set to the file being replaced, narrowed to
                that region.

if you set START and END to the same thing, you deserve everything you get."
  ; Jump to the right buffer.
  (save-current-buffer
    (set-buffer (or buffer (current-buffer)))
    (save-excursion
      ; As long as we haven't applied everything...
      (while substitutions
        ; ... for each substitution, search precisely...
        (let ((subst (car substitutions))
              (case-fold-search nil))
          ; ... from the start of the buffer...
          (goto-char (point-min))
          ; ... for the START regexp...
          (while (re-search-forward (car subst) nil t)
            (let ((start-posn (point)))
              ; ... then find the END regexp...
              (if (re-search-forward (cadr subst) nil t)
                  ; ... and locate the start of that regexp.
                  (let ((end-posn (re-search-backward (cadr subst) nil t)))
                    ; If we are just replacing it with a literal string, do that.
                    (cond
                     ((stringp (caddr subst))
                      (delete-region start-posn end-posn)
                      (insert (caddr subst)))
                     ; If we are calling a function, narrow to the replacement
                     ; zone and do that.
                     ((functionp (caddr subst))
                      (save-restriction
                        (narrow-to-region start-posn end-posn)
                        (funcall (caddr subst))))
                     ; Anything else is a (continuable) error.
                     (t
                      (cerror 'wrong-type-argument (caddr subst)))))))))
        ; Now handle the next substitution.
        (setq substitutions (cdr substitutions))))))

(provide 'auto-edit-substitute)