home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / languages / elisp / packages / edb / db-util.el < prev    next >
Encoding:
Text File  |  1993-06-14  |  38.0 KB  |  1,071 lines

  1. ;;; db-util.el --- part of EDB, the Emacs database
  2.  
  3. ;; See database.el for copyright notice, distribution conditions, etc.
  4.  
  5. ;; Author: Michael Ernst <mernst@theory.lcs.mit.edu>
  6. ;; Keywords: EDB
  7.  
  8. ;;; Commentary:
  9.  
  10. ;; Lisp utilities.
  11. ;; This file is largely cannibalized from util-mde.el and util-mdecl.el,
  12. ;; which are available on request.
  13.  
  14. ;;; Code:
  15.  
  16.  
  17. (provide 'db-util)
  18.  
  19.  
  20.  
  21. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  22. ;;; Bug fixes
  23. ;;;
  24.  
  25. ;; Prevent users of the standard byte-compiler, or users of the new one who
  26. ;; haven't yet loaded bytecomp-runtime.el, from barfing on these macros.
  27. ;; These could probably all be in one test, but this is more satisfying to
  28. ;; paranoid people.
  29.  
  30. ;; This didn't work on all systems when the defuns and defmacros weren't at
  31. ;; top level.
  32. ;;   "No-op for non-users of the Zawinski byte-compiler."
  33. (defmacro proclaim-inline-hack (&rest args)
  34.   )
  35. (if (not (fboundp 'proclaim-inline))
  36.     (fset 'proclaim-inline 'proclaim-inline-hack))
  37. ;;   "No-op for non-users of the Zawinski byte-compiler."
  38. (defmacro proclaim-notinline-hack (&rest args)
  39.   )
  40. (if (not (fboundp 'proclaim-notinline))
  41.     (fset 'proclaim-notinline 'proclaim-notinline-hack))
  42. ;;   "No-op for non-users of the Zawinski byte-compiler."
  43. (defun make-obsolete-hack (fn new)
  44.   )
  45. (if (not (fboundp 'make-obsolete))
  46.     (fset 'make-obsolete 'make-obsolete-hack))
  47. (if (not (fboundp 'inline))
  48.     (progn
  49.       (fset 'inline 'progn)
  50.       (put 'inline 'lisp-indent-hook 0)))
  51. ;;   "No-op for non-users of the Zawinski byte-compiler."
  52. (defun byte-compile-warn-hack (&rest args)
  53.   )
  54. (if (not (fboundp 'byte-compile-warn))
  55.     (fset 'byte-compile-warn 'byte-compile-warn-hack))
  56.  
  57.  
  58. ;; In the standard 18.55 through 18.58 distributions (and maybe more),
  59. ;; backquote has a bug.  Unfortunately, this fix may trounce on other,
  60. ;; correct, implementations of backquote, breaking them.  I don't know how
  61. ;; to correct this, but you can prevent the fix from being loaded by
  62. ;; setting dont-fix-backquote.  I personally use a backquote implementation
  63. ;; that doesn't happen to define the function bq-splicequote.
  64. (defvar dont-fix-backquote nil)
  65. (defvar tailmaker)            ; quiet the byte-compiler
  66. (defvar state)                ; quiet the byte-compiler
  67. (if (or (not dont-fix-backquote) (string-match "^19" emacs-version))
  68.     (progn
  69.       (require 'backquote)
  70.       (defun bq-splicequote (form)
  71.     (setq tailmaker (list form (list 'quote tailmaker)))
  72.     (setq state 'append))))
  73.  
  74.  
  75. ;; Emacs 19 compatibility.
  76. (if (not (fboundp 'buffer-disable-undo))
  77.     (fset 'buffer-disable-undo 'buffer-flush-undo))
  78. (if (not (fboundp 'frame-width))
  79.     (fset 'frame-width 'screen-width))
  80. (if (not (fboundp 'force-mode-line-update))
  81.     (defun force-mode-line-update (&rest args)
  82.       "Force the mode-line of the current buffer to be redisplayed."
  83.       (set-buffer-modified-p (buffer-modified-p))))
  84. (if (not (fboundp 'generate-new-buffer-name))
  85.     ;; By Joe Wells <jbw@cs.bu.edu>
  86.     ;; derived from generate-new-buffer
  87.     (defun generate-new-buffer-name (name)
  88.       (if (not (get-buffer name))
  89.       name
  90.     (let ((count 1)
  91.           (template (concat name "<%d>"))
  92.           tempname)
  93.       (catch 'found
  94.         (while t
  95.           (setq tempname (format template count))
  96.           (if (not (get-buffer tempname))
  97.           (throw 'found tempname))
  98.           (setq count (1+ count))))))))
  99.  
  100.  
  101. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  102. ;;; Searching, matching, and replacing
  103. ;;;
  104.  
  105.  
  106. (defun match-string (n &optional source)
  107.   "Return the string matched by parentheses number N.  If there is a
  108. SOURCE string, return the substring of that string; else, return
  109. substring of the current buffer."
  110.   (cond
  111.    ((stringp source)
  112.     (substring source (match-beginning n) (match-end n)))
  113.    (t (buffer-substring (match-beginning n) (match-end n)))))
  114.  
  115. (defun match-string-maybe (n &optional source)
  116.   "Like match-string, but return nil if there was no match for parenthesis N."
  117.   (and (match-beginning n)
  118.        (match-string n source)))
  119.  
  120.  
  121. (defun unused-char-in-buffer ()
  122.   "Return a character not used in the current buffer, or nil.
  123. This function attempts to return a character that can be displayed in a single
  124. screen column."
  125.   (save-excursion
  126.     (let ((candidate ?\ )
  127.       (result t))
  128.       (while (eq result t)
  129.     (goto-char (point-min))
  130.     (if (not (search-forward (char-to-string candidate) nil t))
  131.         (setq result candidate)
  132.       (progn
  133.         (setq candidate (% (1+ candidate) 256))
  134.         (if (eq candidate ?\ )
  135.         (setq result nil)))))
  136.       result)))
  137.  
  138. (defun unused-char-in-string (string)
  139.   "Return a character not used in STRING, or nil.
  140. This function attempts to return a character that can be displayed in a single
  141. screen column."
  142.   (save-excursion
  143.     (set-buffer (get-buffer-create " *Temporary*"))
  144.     (buffer-disable-undo (current-buffer))
  145.     (erase-buffer)
  146.     (insert string)
  147.     (unused-char-in-buffer)))
  148.  
  149. ;;; Skipping
  150.  
  151. ;; Is this more efficient than regexp-quote and skip-regexp-forward
  152. ;; (which equals looking-at-string and goto-char)?
  153. (defmacro skip-string-forward (string)
  154.   "If point is at STRING, move past it and return non-nil;
  155. otherwise return nil."
  156.   (` (let ((s (, string)))
  157.        (if (equal "" s)
  158.        t
  159.      (if (search-forward s (+ (point) (length s)) t)
  160.          (goto-char (match-end 0)))))))
  161.  
  162. (defmacro skip-string-backward (string)
  163.   "If point is after STRING, move back past it and return t;
  164. otherwise return nil."
  165.   (` (let ((s (, string)))
  166.        (if (equal "" s)
  167.        t
  168.      (search-backward s (- (point) (length s)) t)))))
  169.  
  170. (defmacro skip-regexp-forward (regexp &optional match-no)
  171.   "If point is at REGEXP, move past it and return point;
  172. otherwise return nil.
  173. Point is left at the end of match MATCH-NO if it is specified."
  174.   (` (if (looking-at (, regexp))
  175.      (goto-char (match-end (or (, match-no) 0))))))
  176.  
  177. (defmacro skip-regexp-backward (regexp &optional match-no)
  178.   "If point is after REGEXP, move past it and return point;
  179. otherwise return nil."
  180.   (` (let ((here (point)))
  181.        (if (re-search-backward (, regexp))
  182.        (if (= here (match-end 0))
  183.            t
  184.          (progn
  185.            (goto-char here)
  186.            nil))))))
  187.  
  188.  
  189. ;;; String substitution
  190.  
  191. (defmacro string-substitute (newchar oldchar string)
  192.   "Substitute NEWCHAR for instances of OLDCHAR in STRING.
  193. NEWCHAR and OLDCHAR are characters."
  194.   (` (string-substitute-opt (, newchar)
  195.                 (regexp-quote (char-to-string (, oldchar)))
  196.                 (, string))))
  197.  
  198. ;; Optimized version.  oldchar-regexp should only match one-character strings.
  199. (defun string-substitute-opt (newchar oldchar-regexp string)
  200.   (let ((i -1)
  201.     (case-fold-search nil))
  202.     (while (setq i (string-match oldchar-regexp string (1+ i)))
  203.       (aset string i newchar))))
  204.  
  205.  
  206. ;; Instead of using match-beginning, I could compute the length of the
  207. ;; string and use (backward-char (1- string-length)).
  208. (defun how-many-string-overlapping (string)
  209.   "Return number of matches for STRING following point, including overlapping ones."
  210.   (let ((count 0))
  211.     (save-excursion
  212.      (while (search-forward string nil t)
  213.        (goto-char (1+ (match-beginning 0)))
  214.        (setq count (1+ count))))
  215.     count))
  216.  
  217. (defun how-many-substring-overlapping (substring target)
  218.   "Return number of matches for SUBSTRING in TARGET, including overlapping ones."
  219.   (let ((ss-regexp (regexp-quote substring))
  220.     (count 0)
  221.     (start -1))
  222.     (while (setq start (string-match ss-regexp target (1+ start)))
  223.       (setq count (1+ count)))
  224.     count))
  225.  
  226. ;;; Find-char
  227.  
  228. (defun find-char (char string &optional count)
  229.   "Look for CHAR in STRING; return first index in STRING whose element is CHAR.
  230. If optional arg COUNT is specified, return the COUNTth occurrance."
  231.   (if (not count)
  232.       (setq count 1))
  233.   (let ((index 0)
  234.     (string-length (length string))
  235.     (result nil))
  236.     (while (and (< index string-length) (not result))
  237.       (if (char-equal char (aref string index))
  238.       (if (= count 1)
  239.           (setq result index)
  240.         (setq count (1- count))))
  241.       (setq index (1+ index)))
  242.     result))
  243.  
  244. (defun find-char-from-end (char string &optional count)
  245.   "Look for CHAR in STRING; return last index in STRING whose element is CHAR.
  246. If optional arg COUNT is specified, return the COUNTth occurrance from the end."
  247.   (if (not count)
  248.       (setq count 1))
  249.   (let ((index (1- (length string)))
  250.     (string-length )
  251.     (result nil))
  252.     (while (and (> index -1) (not result))
  253.       (if (char-equal char (aref string index))
  254.       (if (= count 1)
  255.           (setq result index)
  256.         (setq count (1- count))))
  257.       (setq index (1- index)))
  258.     result))
  259.  
  260. (defun string-trim-whitespace (string)
  261.   "Return a substring of STRING with whitespace removed from beginning and end."
  262.   (if (string-match "\\s *\\(.*[^ \t\n]\\)\\s *" string)
  263.       (match-string 1 string)
  264.     ""))
  265. (proclaim-inline string-trim-whitespace)
  266.  
  267.  
  268. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  269. ;;; Structures
  270. ;;;
  271.  
  272. ;;; Simple defstruct originally from BBDB, by Jamie Zawinski <jwz@lucid.com>.
  273.  
  274. ;;; Use it like this:
  275. ;;; (def-db-struct bbdb-phone
  276. ;;;   location area exchange suffix extension)
  277. ;;; (setq this-phone-record (make-vector bbdb-phone-length nil))
  278. ;;; (bbdb-phone-set-exchange this-phone-record 617)
  279. ;;; (bbdb-phone-exchange this-phone-record) ==> 617
  280.  
  281. ;;; Changes by Michael Ernst <mernst@theory.lcs.mit.edu>, March 19, 1992:
  282. ;;;  * added an extra first slot which holds the struct name; this is good
  283. ;;;    for determining a structure's type
  284. ;;;  * added def-db-struct-concatenator to permit greater flexibility in
  285. ;;;    names of accessor functions
  286. ;;;  * added make-foo and foo-p functions
  287.  
  288. ;;; A make- constructor, with default values and overrides, would be nice.
  289. ;;; It might just be best to have the programmer define one by hand, but
  290. ;;; I'm not convinced by that.
  291.  
  292. ;;; Why does it have such a strange name?  Because I want it to start with
  293. ;;; "def", so it shows up in TAGS files, and to end with "struct", so I can
  294. ;;; do M-. struct foo to go to the definition of the foo-bar-baz structure.
  295.  
  296. (defvar def-db-struct-concatenator "-"
  297.   "Inserted between the struct and slot names in slot accessors and setters.
  298. Typical values are \"-\" and \"\".")
  299.  
  300. ;; NAME is a symbol or a list of (symbol (option-name option-value) ...).
  301. (defmacro def-db-struct (name &rest slots)
  302.   "Define NAME as a structure type with a slot for each additional argument.
  303. NAME is a symbol, the name of the new structure, and each slotname is a symbol.
  304. This macro defines functions `make-NAME', `NAME-p', and `copy-NAME' for the
  305. structure, and functions `NAME-SLOTNAME' and `NAME-set-SLOTNAME' to access and
  306. set slots.  It also sets variable  NAME-length  to the number of slots.
  307.  
  308. NAME may also be a list (struct-name (option-name option-value) ...), where
  309. each option-name is a keyword symbol in \{:constructor :predicate :copier\}
  310. and option-value is a symbol, the name that should be used for that
  311. function instead of the defaults listed above."
  312.  
  313.   (let ((body '())
  314.     (i 1)
  315.     (L (length slots))
  316.     conc-name options
  317.     name1 name2 makename predname copyname)
  318.     (if (listp name)
  319.     (setq options (cdr name)
  320.           name (car name)))
  321.     (setq conc-name (concat (symbol-name name)
  322.                 def-db-struct-concatenator))
  323.     (while slots
  324.       (setq name1 (intern (concat conc-name (symbol-name (car slots))))
  325.         name2 (intern (concat conc-name "set-" (symbol-name (car slots))))
  326.         body (nconc body
  327.             (list
  328.              (list 'defmacro name1 '(vector)
  329.                    (list 'list ''aref 'vector i))
  330.              (list 'defmacro name2 '(vector value)
  331.                    (list 'list ''aset 'vector i 'value))
  332.              (list 'put (list 'quote name1)
  333.                    ''edebug-form-hook ''(form))
  334.              (list 'put (list 'quote name2)
  335.                    ''edebug-form-hook ''(form form))
  336.              ))
  337.         slots (cdr slots)
  338.         i (1+ i)))
  339.     (setq makename (or (car (cdr (assoc ':constructor options)))
  340.                (intern (concat "make" def-db-struct-concatenator
  341.                        (symbol-name name))))
  342.       predname (or (car (cdr (assoc ':predicate options)))
  343.                (intern (concat conc-name "p")))
  344.       copyname (or (car (cdr (assoc ':copier options)))
  345.                (intern (concat "copy" def-db-struct-concatenator
  346.                        (symbol-name name)))))
  347.     (setq body (nconc body (list (list 'defconst
  348.                        (intern (concat conc-name "length"))
  349.                        L)
  350.                  (list 'defun makename '()
  351.                        (list 'let (list (list 'result (list 'make-vector (1+ L) nil)))
  352.                          (list 'aset 'result 0
  353.                            (list 'quote name))
  354.                          'result))
  355.                  (list 'put (list 'quote makename)
  356.                        ''edebug-form-hook ''())
  357.                  (list 'defmacro copyname '(struct)
  358.                        '(list 'copy-sequence struct))
  359.                  (list 'put (list 'quote copyname)
  360.                        ''edebug-form-hook ''(form))
  361.                  (list 'defun predname '(object)
  362.                        (concat "T if OBJECT is a "
  363.                            (symbol-name name) ".")
  364.                        (list 'and
  365.                     '(vectorp object)
  366.                     (list '= '(length object) (1+ L))
  367.                     (list 'eq '(aref object 0)
  368.                           (list 'quote name)))))))
  369.     (cons 'progn body)))
  370. (put 'def-db-struct 'edebug-form-spec '(&rest form))
  371.  
  372.  
  373. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  374. ;;; Hooks
  375. ;;;
  376.  
  377. ;;; This is add-to-hook.el by Joe Wells.  It is included here to avoid the
  378. ;;; overhead of yet another file in some Emacs packages.  I've modified the
  379. ;;; function name (to avoid conflicts with other packages) and removed the
  380. ;;; provide statement.
  381.  
  382. ;; ----------------------------------------------------------------------
  383. ;; Created by: Joe Wells, jbw@maverick.uswest.com
  384. ;; Created on: Thu Aug 15 15:40:05 1991
  385. ;; Last modified by: Joe Wells, jbw@maverick.uswest.com
  386. ;; Last modified on: Thu Aug 15 15:43:30 1991
  387. ;; Filename: add-to-hook.el
  388. ;; Purpose: contains add-to-hook function
  389.  
  390. (defun db-add-to-hook (hook-var &rest items)
  391.   "Add to HOOK one or more FUNCTIONS as correctly as possible.
  392. HOOK evaluates to a symbol.
  393.  
  394. This is designed to work only with hooks that are run by run-hooks.
  395. Because of run-hooks flexibility, the value a hook has can take a variety
  396. of forms.  This function tries to deal with all of those forms.  If you
  397. find a case it does not handle, please tell me.
  398.  
  399. After this function is done, the hook variable is a list with each element
  400. one function to be run, regardless of what form the value of the hook took
  401. before."
  402.   (or (symbolp hook-var)
  403.       (error "first argument must be symbol"))
  404.   (or (boundp hook-var)
  405.       (set hook-var nil))
  406.   (let ((hook-value (symbol-value hook-var))
  407.     item)
  408.     (if (or (and (symbolp hook-value)
  409.          ;; should be not eq nil:
  410.          hook-value)
  411.         (and (consp hook-value)
  412.          (eq 'lambda (car hook-value))))
  413.     (setq hook-value (list hook-value)))
  414.     (while (consp items)
  415.       (setq item (car items))
  416.       (or (memq item hook-value)
  417.       (setq hook-value (cons item hook-value)))
  418.       (setq items (cdr items)))
  419.     (set hook-var hook-value)))
  420.  
  421. ;;(provide 'add-to-hook)
  422. ;;----------------------------------------------------------------------
  423.  
  424.  
  425. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  426. ;;; Variables
  427. ;;;
  428.  
  429. ;; Ought to have a way to set the default value, too.
  430. (defmacro deflocalvar (&rest args)
  431.   "Like defvar, but defines a buffer-local variable."
  432.   (` (progn
  433.        (defvar (,@ args))
  434.        (make-variable-buffer-local (quote (, (car args)))))))
  435. (put 'deflocalvar 'edebug-form-spec '(&rest form))
  436.  
  437.  
  438. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  439. ;;; Keys
  440. ;;;
  441.  
  442. ;;; Semi-transparent way to meta-ify a key.  This still isn't quite what we
  443. ;;; want.  The problem is that some patches to permit 8-bit character sets
  444. ;;; to be displayed change meta sequences to escape sequences, even without
  445. ;;; changing meta-flag to nil.
  446.  
  447. (defmacro db-meta-prefix-ify (keys)
  448.   "Prepend `meta-prefix-char' to KEYS, a string."
  449.   (` (concat (list meta-prefix-char) (, keys))))
  450.  
  451.  
  452. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  453. ;;; Functions
  454. ;;;
  455.  
  456. ;; Lifted from edebug 2.7 with very minor modifications.
  457. (defun functionp (object)
  458.   "Return t if OBJECT is a function (is funcallable), nil otherwise."
  459.   (while (and (symbolp object) (fboundp object))
  460.     (setq object (symbol-function object)))
  461.   (or (subrp object)
  462.       (and (listp object)
  463.        (eq (car object) 'lambda)
  464.        (listp (car (cdr object))))))
  465. ;; This can't be a macro because epoch funcalls  (function functionp).
  466. (proclaim-inline functionp)
  467.  
  468. (defun funcall-maybe (fun &rest args)
  469.   "If FUN is non-nil, apply it to ARGS.  Otherwise return second argument,
  470. which would have been the first argument to which FUN was applied.
  471. FUN should be a funcallable object or nil.  Compare to `maybe-funcall'."
  472.   (if fun
  473.       (apply fun args)
  474.     (if args
  475.     (car args))))
  476. (put 'funcall-maybe 'edebug-form-spec '(function &rest form))
  477.  
  478. ;; Perhaps I should change the order of arguments.
  479. (defun funcall-maybe-default (default fun &rest args)
  480.   "If FUN is non-nil, apply it to ARGS.  Otherwise return DEFAULT.
  481. FUN should be a funcallable object or nil."
  482.   (if fun
  483.       (apply fun args)
  484.     default))
  485. (put 'funcall-maybe-default 'edebug-form-spec '(form function &rest form))
  486.  
  487. (defmacro maybe-funcall (fun &rest args)
  488.   "If FUN is non-nil, apply it to ARGS.  Otherwise return nil.
  489. FUN should be a funcallable object or nil.  Compare to `funcall-maybe'."
  490.   (` (funcall-maybe-default nil (, fun) (,@ args))))
  491. (put 'maybe-funcall 'edebug-form-spec '(function &rest form))
  492.  
  493.  
  494. ;; Obviously this could be (easily) generalized to take a list of integers
  495. ;; and to try all of those numbers of arguments; but why would I want that?
  496. (defmacro vararg-call (func noargs1 noargs2 &rest args)
  497.   "Apply FUNC to NOARGS1 (an integer), then (if that fails), to NOARGS2
  498. of the ARGS.  -1 means all arguments.  This macro lets you deal with functions
  499. expecting different numbers of arguments in a uniform way.  Since this is a
  500. macro, don't supply something of the form (function foo) as its first argument;
  501. just supply foo itself."
  502.   (let ((noargs (length args))
  503.     nocommon-args
  504.     common-vars
  505.     common-bindings
  506.     thisvar
  507.     (thisargno 0))
  508.  
  509.     (if (< noargs1 0) (setq noargs1 (- noargs)))
  510.     (if (< noargs2 0) (setq noargs2 (- noargs)))
  511.     (if (not (= (max noargs1 noargs2) noargs))
  512.     (progn
  513.       (byte-compile-warn "`%s' was vararg-called with a maximum of %d arguments, but you supplied %d."
  514.                func (max noargs1 noargs2) noargs)
  515.       (setq args (firstn (max noargs1 noargs2) args))))
  516.     (setq nocommon-args (min noargs1 noargs2))
  517.     (if (= noargs1 noargs2)
  518.     ;; aka (` ((, func) (,@ args)))
  519.     (cons func args)
  520.       (while (< thisargno nocommon-args)
  521.     (setq thisargno (1+ thisargno)
  522.           thisvar (make-symbol (concat "vararg-common-"
  523.                        (int-to-string thisargno)))
  524.           common-vars (cons thisvar common-vars)
  525.           common-bindings (cons (list thisvar (car args)) common-bindings)
  526.           args (cdr args)))
  527.       (setq common-vars (nreverse common-vars)
  528.         common-bindings (nreverse common-bindings))
  529.       (` (let (, common-bindings)
  530.        (condition-case err
  531.            ;; Try calling it with first number of arguments.
  532.            ((, func) (,@ common-vars)
  533.         (,@ (if (< nocommon-args noargs1) args)))
  534.          (wrong-number-of-arguments
  535.           ;; Call it with second number of arguments.
  536.           ((, func) (,@ common-vars)
  537.            (,@ (if (< nocommon-args noargs2) args))))
  538.          (error
  539.           ;; Otherwise resignal; "while t" makes this work under the
  540.           ;; debugger (see, eg, the code for the "error" function).
  541.           (while t
  542.         (signal (car err) (cdr err))))))))))
  543.  
  544. ;; Test cases:
  545. ;; (macroexpand '(vararg-call foo 3 1 bar baz bum))
  546. ;; (macroexpand '(vararg-call foo 3 5 bar baz bum quux quux2))
  547.  
  548.  
  549. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  550. ;;; Files
  551. ;;;
  552.  
  553. (defvar filename-extension-regexp "[^.]\\(\\.\\([-a-z]*\\)\\)$"
  554.   "Submatch 1 is the extension with leading period; submatch 2 is without.")
  555.  
  556. (defun filename-extension (filename &optional period)
  557.   "Return the file extension of FILENAME.
  558. Return nil for extensionless files such as \"foo\".
  559. Return the empty string for files such as \"foo.\".
  560. The leading period is included only if optional arguemnt PERIOD is specified,
  561. in which case nil is never returned."
  562.   (if (string-match filename-extension-regexp filename)
  563.       (substring filename (match-beginning (if period 1 2)))
  564.     (if period
  565.     "")))
  566.  
  567. (defun filename-sans-extension (filename)
  568.   (if (string-match filename-extension-regexp filename)
  569.       (substring filename 0 (match-beginning 1))
  570.     filename))
  571.  
  572. (defun if-file-readable-p (filename)
  573.   "Return FILENAME if the file is readable, nil otherwise."
  574.   (if (file-readable-p filename)
  575.       filename))
  576.  
  577. (defun locate-file-with-extensions (filename extensions)
  578.   "Return the name of a readable file starting with FILENAME
  579. or FILENAME's basename and ending with a string in EXTENSIONS, which is a list.
  580. EXTENSIONS may be nil, in which case FILENAME is searched for as is."
  581.   (if extensions
  582.       (let (result)
  583.     (while (and extensions (not result))
  584.       (setq result (or (if-file-readable-p (concat filename (car extensions)))
  585.                (if-file-readable-p (concat (filename-sans-extension
  586.                             filename)
  587.                                (car extensions))))
  588.         extensions (cdr extensions)))
  589.     result)
  590.     (if-file-readable-p filename)))
  591.  
  592. (defun locate-file-with-extensions-on-path (filename extensions path)
  593.   "Return the name of a readable file starting with FILENAME
  594. or FILENAME's basename and ending with a string in EXTENSIONS, which is a list.
  595. PATH is a list of strings representing directories to be searched in
  596. order after the current one; they may be relative directories.
  597. Nil means the current directory."
  598.   (or (locate-file-with-extensions filename extensions)
  599.       (let ((filename-directory (file-name-directory filename))
  600.         (filename-nondirectory (file-name-nondirectory filename))
  601.         result candidate-directory)
  602.     (while (and path (not result))
  603.       (setq candidate-directory (if (car path)
  604.                     (file-name-as-directory (car path))
  605.                       default-directory)
  606.         path (cdr path)
  607.         result (locate-file-with-extensions
  608.             ;; This check is so we return something reasonable,
  609.             ;; not because the code requires the simpler form.
  610.             (if (file-name-absolute-p candidate-directory)
  611.                 (concat candidate-directory filename-nondirectory)
  612.               ;; This probably only works on Unix.
  613.               (concat filename-directory candidate-directory
  614.                   filename-nondirectory))
  615.             extensions)))
  616.     result)))
  617.  
  618. (defun locate-file-on-path (filename path)
  619.   "Return the full path of a file named FILENAME located
  620. in the current directory or on PATH, which is a list of directories (strings)
  621. or nil for the current directory."
  622.   (locate-file-with-extensions-on-path filename nil path))
  623.  
  624.  
  625. (defun same-file-p (file1 file2)
  626.   "Return t if FILE1 and FILE2 are names for the same file."
  627.   (setq file1 (file-resolve-symlink file1)
  628.     file2 (file-resolve-symlink file2))
  629.   (or (equal file1 file2)
  630.       (equal file1 (file-name-nondirectory file2))
  631.       (equal file2 (file-name-nondirectory file1))
  632.       ;; Works for hard links.  If neither file exists, attributes are nil
  633.       ;; and so trivially equal.
  634.       (and (file-exists-p file1) (file-exists-p file2)
  635.        (equal (file-attributes file1)
  636.           (file-attributes file2)))))
  637.  
  638. (defun file-resolve-symlink (file)
  639.   "Return the non-link FILE eventually points to, or FILE if it's not a symbolic link.
  640. This gets in an infinite loop if FILE points into a circular list of symlinks."
  641.   (while (file-symlink-p file)
  642.     (setq file (expand-file-name (car (file-attributes file))
  643.                  (file-name-directory file))))
  644.   file)
  645.  
  646.  
  647. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  648. ;;; Conversion
  649. ;;;
  650.  
  651. ;; string-to-int is unacceptable because it returns 0 for unparseable values.
  652.  
  653. (defun string->integer-default (string &optional default)
  654.   "If STRING represents an integer, return it; otherwise return DEFAULT."
  655.   (let ((result (condition-case nil
  656.             (car (read-from-string string))
  657.           (error nil))))
  658.     (if (integerp result)
  659.     result
  660.       default)))
  661. (fset 'string->number-default (symbol-function 'string->integer-default))
  662.  
  663. (defun string->integer-or-nil (string)
  664.   (string->integer-default string nil))
  665. (fset 'string->number-or-nil (symbol-function 'string->integer-or-nil))
  666.  
  667. (defun string->integer (string)
  668.   "Return the integer represented by STRING, or err.
  669. See also `string->integer-default'."
  670.   (or (string->integer-or-nil string)
  671.       (error "string->integer:  `%s' doesn't look like an integer." string)))
  672. (fset 'string->number (symbol-function 'string->integer))
  673.  
  674.  
  675. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  676. ;;; Buffers
  677. ;;;
  678.  
  679. ;;; This macro duplicates BODY.  This should be fixed.
  680. ;; This version, which works when body moves point in a buffer displayed in
  681. ;; a window other than the selected window, is from Joe Wells
  682. ;; <jbw@cs.bu.edu>.  (If Lisp code moves point in a buffer displayed in a
  683. ;; window other than the selected window, Emacs kindly restores point in
  684. ;; the buffer to its window's version of point.)
  685. (defmacro in-buffer (buffer &rest body)
  686.   "Executes, in BUFFER, forms of BODY."
  687.   ;; Need get-buffer-create because BUFFER might be a string.
  688.   (` (let ((target-buffer (get-buffer-create (, buffer)))
  689.        (this-buffer (current-buffer)))
  690.        (if (eq target-buffer this-buffer)
  691.        (progn
  692.          (,@ body))
  693.      ;; Can't use save-excursion here because we only want to save the
  694.      ;; current buffer, not its value for point.
  695.      (unwind-protect
  696.          (progn
  697.            (set-buffer target-buffer)
  698.            (let* ((target-window (get-buffer-window target-buffer))
  699.               (track-window-point-p
  700.                (and (not (eq target-window (selected-window)))
  701.                 (eq (window-point target-window) (point)))))
  702.          (prog1
  703.              (progn
  704.                (,@ body))
  705.            (if (and track-window-point-p
  706.                 ;; *** Do I need this check?
  707.                 (eq (current-buffer) target-buffer)
  708.                 (eq target-window (get-buffer-window target-buffer))
  709.                 (not (eq target-window (selected-window))))
  710.                (set-window-point target-window (point))))))
  711.        (if (and (bufferp this-buffer)
  712.             (buffer-name this-buffer))
  713.            (set-buffer this-buffer)))))))
  714. (put 'in-buffer 'lisp-indent-hook 1)
  715. (put 'in-buffer 'edebug-form-spec '(&rest form))
  716.  
  717. (defmacro in-window (window &rest body)
  718.   "Executes, in WINDOW, forms of BODY.
  719. This is more useful than `in-buffer' for window manipulation, as by `scroll-up'."
  720.   (` (let ((this-window (selected-window)))
  721.        (unwind-protect
  722.        (progn
  723.          (select-window (, window))
  724.          (,@ body))
  725.      (select-window this-window)))))  
  726. (put 'in-window 'lisp-indent-hook 1)
  727. (put 'in-window 'edebug-form-spec '(&rest form))
  728.  
  729.  
  730. ;; Similar tricks can be done with syntax-table and current-local-map.
  731. ;; Adapted from code by Joe Wells.
  732. (defun copy-buffer-local-variables (buffer)
  733.   "Copy the values of all of BUFFER's local variables into the current buffer."
  734.   (let ((blv (in-buffer buffer (buffer-local-variables)))
  735.     pair symbol)
  736.     (while (consp blv)
  737.       (setq pair (car blv))
  738.       (setq symbol (car pair))
  739.       (if (memq symbol '(0 buffer-undo-list)) ; 18.57 brain-damage!!!!!
  740.       nil
  741.     (progn
  742.       (if (not (and symbol (symbolp symbol))) (error "impossible"))
  743.       (make-local-variable symbol)
  744.       (set symbol (cdr pair))))
  745.       (setq blv (cdr blv)))))
  746.  
  747.  
  748. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  749. ;;; Windows
  750. ;;;
  751.  
  752. ;; I'm not sure whether this works if the last line is wrapped.
  753. ;; Likewise for bob-visible-p and wrapped first line (is that possible?).
  754. (defun eob-visible-p ()
  755.   (save-excursion
  756.     (let ((ht (window-height (selected-window))))
  757.       (move-to-window-line (- ht 2))
  758.       (end-of-line)
  759.       (eobp))))
  760.  
  761. (defun bob-visible-p ()
  762.   (save-excursion
  763.     (move-to-window-line 0)
  764.     (beginning-of-line)
  765.     (bobp)))
  766.  
  767.  
  768. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  769. ;;; Strings
  770. ;;;
  771.  
  772. (defun string-substitute-substring-general-case (new old-regexp string)
  773.   "Call `string-replace-regexp-2'.  Beware special meaning of \\!."
  774.   (string-replace-regexp-2 string old-regexp new))
  775.  
  776. ;; If much replacement is going to happen, this is more efficient.
  777. ;; Original version from gaynor@brushfire.rutgers.edu (Silver).
  778. (defun string-replace-regexp-2 (string regexp replacement)
  779.   "Return the string resulting by replacing all of STRING's instances of REGEXP
  780. with REPLACEMENT."
  781.   (save-excursion
  782.     (set-buffer (get-buffer-create " *Temporary*"))
  783.     (buffer-disable-undo (current-buffer))
  784.     (erase-buffer)
  785.     (save-excursion (insert string))
  786.     (while (re-search-forward regexp nil t)
  787.       (replace-match replacement))
  788.     (buffer-string)
  789.     ))
  790.  
  791. ;; It would be nice to make the delimiter an optional argument to these.
  792.  
  793. ;; A syntax table implementation would be too complicated, so hardcode space
  794. ;; and tab.
  795. (defun string-split-last-word (splitee &optional exceptions delimiter)
  796.   "Return list of two strings (all-but-last-word last-word).
  797. If there is only one word, return (SPLITEE \"\").
  798. The result strings can be concatenated to return the original string,
  799. with the exception of some number (at least one) of spaces and tabs,
  800. and possibly a comma immediately preceding them.
  801. Optional arg EXCEPTIONS, if non-nil, is a regexp (containing spaces or tabs)
  802. which, if found at the end of SPLITEE, should be considered a single word.
  803. Optional arg DELIMITER, if non-nil, is used instead of the default word
  804. delimiter.  It should be a regexp."
  805.   (if (not delimiter) (setq delimiter ",?[ \t]+"))
  806.   (if (or (and exceptions
  807.            (string-match (concat delimiter "\\(" exceptions "\\)$") splitee))
  808.       (string-match (concat delimiter "\\([a-zA-Z0-9'-]+\\)$") splitee))
  809.       (list (substring splitee 0 (match-beginning 0))
  810.         (substring splitee (match-beginning 1)))
  811.     (list splitee "")))
  812.  
  813. ;; maybe what I really want is string-to-word-list
  814. (defun string-split-first-word (splitee &optional delimiter)
  815.   "Return list of strings (first-word remaining-words).
  816. Argument SPLITEE is split at the first sequence of spaces and tabs.
  817. Optional arg DELIMITER, if non-nil, is used instead of the default word
  818. delimiter.  It should be a regexp."
  819.   (if (string-match (or delimiter "[ \t]+") splitee)
  820.       (list (substring splitee 0 (match-beginning 0))
  821.         (substring splitee (match-end 0)))
  822.     (list splitee "")))
  823.  
  824. (defun count-array (item array)
  825.   "Return the number of times that ITEM appears in ARRAY; test with `equal'."
  826.   (let ((limit (length array))
  827.     (result 0)
  828.     (index 0))
  829.     (while (< index limit)
  830.       (if (equal item (aref array index))
  831.       (setq result (1+ result)))
  832.       (setq index (1+ index)))
  833.     result))
  834.  
  835.  
  836. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  837. ;;; Lists
  838. ;;;
  839.  
  840. ;; Which should come first, N or LIST?
  841. (defun firstn (n list)
  842.   "Return a copy of the first N elements of LIST."
  843.   (let ((result '()))
  844.     (while (and list (> n 0))
  845.       (setq result (cons (car list) result)
  846.         n (1- n)
  847.         list (cdr list)))
  848.     (nreverse result)))
  849.  
  850. ;; from bytecomp.el
  851. (or (and (fboundp 'member)
  852.      ;; avoid using someone else's possibly bogus definition of this.
  853.      (subrp (symbol-function 'member)))
  854.     (defun member (elt list)
  855.       "like memq, but uses equal instead of eq.  In v19, this is a subr."
  856.       (while (and list (not (equal elt (car list))))
  857.     (setq list (cdr list)))
  858.       list))
  859.  
  860. ;;; Emacs provides rassq, but rassoc is nice to have too.
  861. (defun rassoc (elt list)
  862.   "Return non-nil if ELT is the cdr of an element of LIST.  Comparison done with  `equal'.
  863. The value is actually the element of LIST whose cdr is ELT."
  864.   (let (result)
  865.     (while list
  866.       (if (equal elt (cdr (car list)))
  867.       (setq result (car list)
  868.         list nil)
  869.     (setq list (cdr list))))
  870.     result))
  871.  
  872.  
  873. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  874. ;;; Messages
  875. ;;;
  876.  
  877. (defvar use-electric-help-p nil
  878.   "*Non-nil if Emacs programs should use electric help where possible.
  879. Don't set this to a non-nil value unless the ehelp package is available.")
  880.  
  881. ;; Regrettably, this produces big code by including its argument twice.
  882. (defmacro with-electric-help-maybe (&rest body)
  883.   "Similar to `with-electric-help' if `use-electric-help-p' is non-nil;
  884. otherwise like `with-output-to-temp-buffer' with the \"*Help*\" buffer.
  885. Ehelp is loaded if necessary.
  886. BODY is not a thunk (a function of no arguments) but simply a set of forms."
  887.   (` (if use-electric-help-p
  888.      (progn
  889.        (require 'ehelp)
  890.        (with-electric-help
  891.         (function (lambda ()
  892.             (,@ body)))))
  893.        (with-output-to-temp-buffer "*Help*"
  894.      (,@ body)))))
  895.  
  896. ;; Originally by Joe Wells <jbw@cs.bu.edu>
  897. (defun best-fit-message (text &optional buffer)
  898.   "Show TEXT in echo area if it fits or in optional BUFFER (default *Message*)."
  899.   (or buffer (setq buffer "*Message*"))
  900.   (save-excursion
  901.     (set-buffer (get-buffer-create " temp printing buffer"))
  902.     (erase-buffer)
  903.     (buffer-disable-undo (current-buffer))
  904.     (insert text)
  905.     (delete-region (point)
  906.            (progn
  907.              (skip-chars-backward " \t\n")
  908.              (point)))
  909.     (cond ((and (< (current-column) (frame-width))
  910.         (progn
  911.           (beginning-of-line 1)
  912.           (bobp)))
  913.        ;; This can't be just buffer, even though that's non-nil,
  914.        ;; because it might not be an existing buffer.
  915.        (delete-windows-on (get-buffer-create buffer))
  916.        (message "%s" (buffer-substring (point-min) (point-max))))
  917.       (t
  918.        (with-electric-help-maybe
  919.         (princ text))))))
  920.  
  921.  
  922. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  923. ;;; Cursor movement
  924. ;;;
  925.  
  926. (defun forward-line-wrapping (arg)
  927.   "Like forward-line, but wrap around to the beginning of the buffer if
  928. it encounters the end."
  929.   (interactive "p")
  930.   (let ((to-go (forward-line arg)))
  931.     (cond ((or (> to-go 0) (not (bolp)))
  932.        (goto-char (point-min))
  933.        (forward-line-wrapping to-go))
  934.       ((< to-go 0)
  935.        (goto-char (point-max))
  936.        (forward-line-wrapping (1+ to-go))))))
  937.  
  938. (defun current-line ()
  939.   "Return the line number of the line containing point."
  940.   (save-restriction
  941.     (widen)
  942.     (save-excursion
  943.       (beginning-of-line)
  944.       (1+ (count-lines 1 (point))))))
  945.  
  946.  
  947. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  948. ;;; Buffer substitution
  949. ;;;
  950.  
  951. (defun buffer-substitute (substitutions backward check)
  952.   "Make replacements in the current buffer according to SUBSTITUTIONS.
  953.   SUBSTITUTIONS is list of pairs of strings; the cdr of each pair will be
  954. substituted for the car, in order, unless optional argument BACKWARD is
  955. non-nil, in which case the car is substituted for the cdr and the
  956. substitutions are done in reverse order.
  957.   If optional third argument CHECK is non-nil, the user is warned if any of
  958. the substituted-in strings already appears in the buffer; such a situation
  959. would make substitution, then unsubstitution, not yield a result identical
  960. to the original buffer, since all instances of the substituted-in string
  961. will be assumed on the reverse substitution to have been the result of
  962. replacing a substituted-for string.
  963.   Return nil if CHECK is nil or there were no ambiguities; otherwise
  964. return a list of replacements creating ambiguity."
  965.  
  966.   (if backward
  967.       (setq substitutions (mapcar (function (lambda (sub-cons)
  968.                      (cons (cdr sub-cons) (car sub-cons))))
  969.                   (reverse substitutions))))
  970.     ;;; Much too tricky, and modified the argument besides.
  971.     ;; (let ((subs (reverse substitutions))
  972.     ;;         temp)
  973.     ;;     (while subs
  974.     ;;       (setq temp (caar subs))
  975.     ;;       (setcar (car subs) (cdar subs))
  976.     ;;       (setcdr (car subs) temp)
  977.     ;;       (setq subs (cdr subs)))
  978.     ;;     (setq substitutions (nreverse substitutions)))
  979.  
  980.   ;; (message "buffer-substitute:  substitutions = %s" substitutions)
  981.  
  982.   ;; Should do all checking before any substitutions are done.
  983.   ;; Bad:
  984.   ;;  * any to-string appears in text, unless it's an earlier from-string.
  985.   ;;  * any to-string appears in previous to-string without intervening
  986.   ;;    from-string.  (but then it's just stupidly inefficient)
  987.  
  988.   ;; Perhaps be able to override checks of the substitutions pairs.  Such
  989.   ;; checks will be hairy anyway because we may create an ambiguity by
  990.   ;; replacing part of a match such that the other part is still in the
  991.   ;; buffer unchanged.  With one-character stuff this is obviously much
  992.   ;; easier.
  993.   ;; Perhaps do the checks by character...?
  994.  
  995.   ;; Don't want to do checks as we do the substitutions because that leaves
  996.   ;; us in a bad state:  the work is partially done.  We want to let the
  997.   ;; guy know before we start.
  998.  
  999.   ;; If, in the case of an ambiguity, we're just going to give up anyway,
  1000.   ;; then perhaps it isn't so bad to do the checks after part of the work
  1001.   ;; is done (except that the work already done would have been a waste of
  1002.   ;; time).  So maybe make the check of the pairs a preliminary one and do
  1003.   ;; the real check as we go.  But in some cases such checks won't be
  1004.   ;; necessary.
  1005.  
  1006.   ;; Perhaps if we want checks on the substitution strings themselves, then
  1007.   ;; do that separately beforehand and call this with check = nil.
  1008.  
  1009.   ;; And hey, searching for one instance of a string is pretty cheap, after
  1010.   ;; all.  And I don't expect to be calling this with a truly enormous list
  1011.   ;; of substitutions anyway.
  1012.  
  1013.   ;; I think I'm being too paranoid here.  In many cases I'm not even going
  1014.   ;; to call this with check = t.
  1015.  
  1016.   (let (from-string to-string ambiguity ambiguities)
  1017.     (while substitutions
  1018.       (setq from-string (car (car substitutions))
  1019.         to-string (cdr (car substitutions)))
  1020.       ;; (message "Substituting %s for %s." to-string from-string)
  1021.       (goto-char (point-min))
  1022.  
  1023.       (if (and check (search-forward to-string nil t))
  1024.       (progn
  1025.         (setq ambiguity (car substitutions))
  1026.         (goto-char (point-min))))
  1027.  
  1028.       (replace-string from-string to-string)
  1029.  
  1030.       ;; Don't complain if we didn't actually do any substitution.
  1031.       (if ambiguity
  1032.       (progn
  1033.         (if (not (= (point) (point-min)))
  1034.         (setq ambiguities (cons ambiguity ambiguities)))
  1035.         (setq ambiguity nil)))
  1036.  
  1037.       (setq substitutions (cdr substitutions)))
  1038.     ambiguities))
  1039.  
  1040.  
  1041. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1042. ;;; File local variables
  1043. ;;;
  1044.  
  1045. (defun operate-on-local-variables (region-function)
  1046.   "Apply REGION-FUNCTION to the local-variables region of the buffer.
  1047. Return t if a local-variables region was found; REGION-FUNCTION should act
  1048. by side effect."
  1049.   (goto-char (point-max))
  1050.   (search-backward "\n\^L"
  1051.            (max (- (point-max) 3000) (point-min)) 'move)
  1052.   (if (search-forward "Local Variables:" nil t)
  1053.       (progn
  1054.     (beginning-of-line 1)
  1055.     (funcall region-function (point) (point-max))
  1056.     t)))
  1057.  
  1058. (defun really-hack-local-variables ()
  1059.   "Call `hack-local-variables', ignoring variables that limit it."
  1060.   ;; Bah!  Hulk not impressed by puny attempts to thwart him!
  1061.   (let ((ignore-local-eval nil)        ; Emacs 18
  1062.     (enable-local-eval t)        ; Emacs 19
  1063.     ;; Emacs 19 hack-local-variables doesn't take an argument, so set this.
  1064.     (inhibit-local-variables nil))
  1065.     (hack-local-variables)))
  1066.  
  1067.  
  1068. ;; This page feed is to defeat local variables processing.
  1069.  
  1070. ;;; db-util.el ends here
  1071.