view lisp/compat.el @ 558:ed498ef2108b

[xemacs-hg @ 2001-05-23 09:59:33 by ben] xemacs.mak: call `ver' to get the exact os version and put it in the installation; suggestion from adrian. behavior-defs.el: Add scroll-in-place, jka-compr, efs, fix up some things. pop.c: Remove BROKEN_CYGWIN. etc\sample.init.el: Rewrite to be much more careful about loading features -- now it decays gracefully even in the complete absence of packages. Also avoid doing obnoxious things when loading efs. configure.in: add some support for eventually turning on file coding by default. Fix numerous places where AC_MSG_WARN had quotes around its arg, which is bad. Replace with []. Same for AC_MSG_ERROR. s\cygwin32.h, s\mingw32.h: remove support for way old beta versions of cygwin. don't put -Wno-sign-compare in the system switches; this isn't a system issue. define BROKEN_SIGIO for cygwin to get C-g support. device-msw.c: signal an error rather than crash with an unavailable network printer (from Mike Alexander). event-msw.c: cleanup headers. fix (hopefully) an error with data corruption when sending to a network connection. fileio.c: Fix evil code that attempts to handle the ~user prefix by (a) always assuming we're referencing ourselves and not even verifying the user -- hence any file with a tilde as its first char is invalid! (b) if there wasn't a slash following the filename, the pointer was set *past* the end of file and we started reading from uninitialized memory. Now we simply treat these as files, always. optionally for 21.4 (doc fix): lread.c: cambia de pas_de_lache_ici -- al minimo usa la palabra certa. frame.c: fix warnings. emacs.c, nt.c, ntproc.c, process-nt.c, realpath.c, unexnt.c: rename MAX_PATH to standard PATH_MAX. process-nt.c, realpath.c: cleanup headers. process-unix.c, sysdep.c, systime.h, syswindows.h: kill BROKEN_CYGWIN and support for way old beta versions of cygwin. sysfile.h: use _MAX_PATH (Windows) preferentially for PATH_MAX if defined. include io.h on Cygwin (we need get_osfhandle()). include sys/fcntl.h always, since we were including it in various header files anyway. unexcw.c: fix up style to conform to standard. remove duplicate definition of PERROR. buffer.c: comment change. database.c, debug.h, device-tty.c, dired-msw.c, glyphs-msw.c: header cleanups (remove places that directly include a system header file, because we have our own layer to do this more cleanly and portably); indentation fixes.
author ben
date Wed, 23 May 2001 09:59:48 +0000
parents de805c49cfc1
children 6728e641994e
line wrap: on
line source

;;; compat.el --- Mechanism for non-intrusively providing compatibility funs.

;; Copyright (C) 2000 Ben Wing.

;; Author: Ben Wing <ben@xemacs.org>
;; Maintainer: Ben Wing
;; Keywords: internal

;; This file is part of XEmacs.

;; XEmacs 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, or (at your option)
;; any later version.

;; XEmacs is distributed in the hope that it will be useful, but
;; WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
;; General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with XEmacs; see the file COPYING.  If not, write to the 
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.

;;; Synched up with: Not in FSF.

;;; Authorship:

; Written May 2000 by Ben Wing.

;;; Commentary:

;; Typical usage:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 1. Wrap modules that define compatibility functions like this:     ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;(compat-define-group 'fsf-compat)

;(compat-define-functions 'fsf-compat

;(defun overlayp (object)
;  "Return t if OBJECT is an overlay."
;  (and (extentp object)
;       (extent-property object 'overlay)))

;(defun make-overlay (beg end &optional buffer front-advance rear-advance)
;  ...)

;...

;) ;; end of (compat-define-group 'fsf-compat)

;;;; overlay.el ends here


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 2. Wrap modules that use the compatibility functions like this:    ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;(compat 'fsf-compat

;(defun random-module-my-fun (bar baz)
;  (if (fboundp 'overlays-in) (overlays-in bar baz)))

;...

;) ;; end of (compat 'fsf-compat)

;;;; random-module.el ends here


(defun compat-hash-table (group)
  (get group 'compat-table))

(defun compat-make-hash-table (group)
  (put group 'compat-table (make-hash-table)))

(defmacro compat-define-group (group)
  "Define GROUP as a group of compatibility functions.
Individual functions are defined using `compat-define-functions'.
Once defined, the functions can be used by wrapping your code in the
`compat' macro.

If GROUP is already defined, nothing happens."
  (let ((group (eval group)))
    (or (hash-table-p (compat-hash-table group))
	(compat-make-hash-table group))))

(defmacro compat-clear-functions (group)
  "Clear all defined functions and macros out of GROUP."
  (let ((group (eval group)))
    (clrhash (compat-hash-table group))))

(defmacro compat-define-functions (group &rest body)
  "Define compatibility functions in GROUP.
You should simply wrap this around the code that defines the functions.
Any functions and macros defined at top level using `defun' or `defmacro'
will be noticed and added to GROUP.  Other top-level code will be executed
normally.  All code and definitions in this group can safely reference any
other functions in this group -- the code is effectively wrapped in a
`compat' call.  You can call `compat-define-functions' more than once, if
necessary, for a single group.

What actually happens is that the functions and macros defined here are in
fact defined using names prefixed with GROUP.  To use these functions,
wrap any calling code with the `compat' macro, which lexically renames
the function and macro calls appropriately."
  (let ((group (eval group)))
    (let (fundef
	  (body-tail body))
      (while body-tail
	(setq fundef (car body-tail))
	(when (and (consp fundef) (eq (car fundef) 'defun))
	  (puthash (second fundef) (third fundef) (compat-hash-table group)))
	(when (and (consp fundef) (eq (car fundef) 'defmacro))
	  (puthash (second fundef) (third fundef) (compat-hash-table group)))
	(setq body-tail (cdr body-tail))))
    (let (fundef
	  (body-tail body)
	  result)
      (while body-tail
	(setq fundef (car body-tail))
	(push
	 (cond ((and (consp fundef) (eq (car fundef) 'defun))
		(nconc (list 'defun
			      (intern (concat (symbol-name group) "-"
					      (symbol-name (second fundef))))
			      (third fundef))
			(nthcdr 3 fundef)))
	       ((and (consp fundef) (eq (car fundef) 'defmacro))
		(nconc (list 'defmacro
			      (intern (concat (symbol-name group) "-"
					      (symbol-name (second fundef))))
			      (third fundef))
			(nthcdr 3 fundef)))
	       (t fundef))
	 result)
	(setq body-tail (cdr body-tail)))
      (nconc (list 'compat (list 'quote group)) (nreverse result)))))

(defvar compat-active-groups nil)

(defun compat-fboundp (groups fun)
  "T if FUN is either `fboundp' or one of the compatibility funs in GROUPS.
GROUPS is a list of compatibility groups as defined using
`compat-define-group'."
  (or (fboundp fun)
      (block nil
	(mapcar #'(lambda (group)
		    (if (gethash fun (compat-hash-table group))
			(return t)))
		groups))))

(defmacro compat (group &rest body)
  "Make use of compatibility functions and macros in GROUP.
You should simply wrap this around the code that uses the functions
and macros in GROUP.  Typically, a call to `compat' should be placed
at the top of an ELisp module, with the closing parenthesis at the
bottom; use this in place of a `require' statement.  Wrapped code can
be either function or macro definitions or other ELisp code, and
wrapped function or macro definitions need not be at top level.  All
calls to the compatibility functions or macros will be noticed anywhere
within the wrapped code.  Calls to `fboundp' within the wrapped code
will also behave correctly when called on compatibility functions and
macros, even though they would return nil elsewhere (including in code
in other modules called dynamically from the wrapped code).

The functions and macros define in GROUP are actually defined under
prefixed names, to avoid namespace clashes and bad interactions with
other code that calls `fboundp'.  All calls inside of the wrapped code
to the compatibility functions and macros in GROUP are lexically
mapped to the prefixed names.  Since this is a lexical mapping, code
in other modules that is called by functions in this module will not
be affected."
  (let ((group (eval group))
	defs)
    (maphash
     #'(lambda (fun args)
	 (push
	  (list fun args
		(nconc
		 (list 'list
		       (list 'quote 
			     (intern (concat (symbol-name group) "-"
					     (symbol-name fun)))))
		 args))
	  defs))
     (compat-hash-table group))
    ;; it would be cleaner to use `lexical-let' instead of `let', but that
    ;; causes function definitions to have obnoxious, unreadable junk in
    ;; them.  #### Move `lexical-let' into C!!!
    `(let ((compat-active-groups (cons ',group compat-active-groups)))
       (macrolet ((fboundp (fun) `(compat-fboundp ',compat-active-groups ,fun))
		  ,@defs)
	 ,@body))))