home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 2: Applications / Linux Cubed Series 2 - Applications.iso / editors / emacs / xemacs / xemacs-1.006 / xemacs-1 / lib / xemacs-19.13 / lisp / prim / specifier.el < prev    next >
Encoding:
Text File  |  1995-06-21  |  10.5 KB  |  287 lines

  1. ;;; specifier.el --- Lisp interface to specifiers
  2. ;; Keywords: internal
  3.  
  4. ;; Copyright (C) 1995 Ben Wing
  5.  
  6. ;; Author: Ben Wing <wing@netcom.com>
  7.  
  8. ;; This file is part of XEmacs.
  9.  
  10. ;; XEmacs is free software; you can redistribute it and/or modify it
  11. ;; under the terms of the GNU General Public License as published by
  12. ;; the Free Software Foundation; either version 2, or (at your option)
  13. ;; any later version.
  14.  
  15. ;; XEmacs is distributed in the hope that it will be useful, but
  16. ;; WITHOUT ANY WARRANTY; without even the implied warranty of
  17. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  18. ;; General Public License for more details.
  19.  
  20. ;; You should have received a copy of the GNU General Public License
  21. ;; along with XEmacs; see the file COPYING.  If not, write to the Free
  22. ;; Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  23.  
  24. (defun make-specifier-and-init (type spec-list &optional dont-canonicalize)
  25.   "Create and initialize a new specifier.
  26.  
  27. This is a front-end onto `make-specifier' that allows you to create a
  28. specifier and add specs to it at the same time.  TYPE specifies the
  29. specifier type.  SPEC-LIST supplies the specification(s) to be added
  30. to the specifier. Normally, almost any reasonable abbreviation of the
  31. full spec-list form is accepted, and is converted to the full form;
  32. however, if optional argument DONT-CANONICALIZE is non-nil, this
  33. conversion is not performed, and the SPEC-LIST must already be in full
  34. form.  See `canonicalize-spec-list'."
  35.   (let ((sp (make-specifier type)))
  36.     (if (not dont-canonicalize)
  37.     (setq spec-list (canonicalize-spec-list spec-list type)))
  38.     (add-spec-list-to-specifier sp spec-list)
  39.     sp))
  40.  
  41. ;; God damn, do I hate dynamic scoping.
  42.  
  43. (defun map-specifier (ms-specifier ms-func &optional ms-locale ms-maparg)
  44.   "Apply MS-FUNC to the specification(s) for MS-LOCALE in MS-SPECIFIER.
  45.  
  46. If MS-LOCALE is a locale, MS-FUNC will be called for that locale.
  47. If MS-LOCALE is a locale type, MS-FUNC will be mapped over all locales
  48. of that type.  If MS-LOCALE is 'all or nil, MS-FUNC will be mapped
  49. over all locales in MS-SPECIFIER.
  50.  
  51. MS-FUNC is called with four arguments: the MS-SPECIFIER, the locale
  52. being mapped over, the inst-list for that locale, and the
  53. optional MS-MAPARG.  If any invocation of MS-FUNC returns non-nil,
  54. the mapping will stop and the returned value becomes the
  55. value returned from `map-specifier'.  Otherwise, `map-specifier'
  56. returns nil."
  57.   (let ((ms-specs (specifier-spec-list ms-specifier ms-locale))
  58.     ms-result)
  59.     (while (and ms-specs (not ms-result))
  60.       (let ((ms-this-spec (car ms-specs)))
  61.     (setq ms-result (funcall ms-func ms-specifier (car ms-this-spec)
  62.                   (cdr ms-this-spec) ms-maparg))
  63.     (setq ms-specs (cdr ms-specs))))
  64.     ms-result))
  65.  
  66. (defun canonicalize-inst-pair (inst-pair specifier-type &optional noerror)
  67.   "Canonicalize the given INST-PAIR.
  68.  
  69. SPECIFIER-TYPE specifies the type of specifier that this SPEC-LIST
  70. will be used for.
  71.  
  72. Canonicalizing means converting to the full form for an inst-pair, i.e.
  73. `(TAG-SET . INSTANTIATOR)'.  A single, untagged instantiator is given
  74. a tag set of nil (the empty set), and a single tag is converted into
  75. a tag set consisting only of that tag.
  76.  
  77. If NOERROR is non-nil, signal an error if the inst-pair is invalid;
  78. otherwise return t."
  79.   ;; OK, the possibilities are:
  80.   ;;
  81.   ;; a) a single instantiator
  82.   ;; b) a cons of a tag and an instantiator
  83.   ;; c) a cons of a tag set and an instantiator
  84.   (cond ((valid-instantiator-p inst-pair specifier-type)
  85.      ;; case (a)
  86.      (cons nil inst-pair))
  87.  
  88.     ((not (consp inst-pair))
  89.      ;; not an inst-pair
  90.      (if noerror t
  91.        ;; this will signal an appropriate error.
  92.        (check-valid-instantiator inst-pair specifier-type)))
  93.  
  94.     ((and (valid-specifier-tag-p (car inst-pair))
  95.           (valid-instantiator-p (cdr inst-pair) specifier-type))
  96.      ;; case (b)
  97.      (cons (list (car inst-pair)) (cdr inst-pair)))
  98.  
  99.     ((and (valid-specifier-tag-set-p (car inst-pair))
  100.           (valid-instantiator-p (cdr inst-pair) specifier-type))
  101.      ;; case (c)
  102.      inst-pair)
  103.      
  104.     (t
  105.      (if noerror t
  106.        (signal 'error (list "Invalid specifier tag set"
  107.                 (car inst-pair)))))))
  108.  
  109. (defun canonicalize-inst-list (inst-list specifier-type &optional noerror)
  110.   "Canonicalize the given INST-LIST (a list of inst-pairs).
  111.  
  112. SPECIFIER-TYPE specifies the type of specifier that this INST-LIST
  113. will be used for.
  114.  
  115. Canonicalizing means converting to the full form for an inst-list, i.e.
  116. `((TAG-SET . INSTANTIATOR) ...)'.  This function accepts a single
  117. inst-pair or any abbrevation thereof or a list of (possibly
  118. abbreviated) inst-pairs. (See `canonicalize-inst-pair'.)
  119.  
  120. If NOERROR is non-nil, signal an error if the inst-list is invalid;
  121. otherwise return t."
  122.  
  123.   ;; OK, the possibilities are:
  124.   ;;
  125.   ;; a) an inst-pair or various abbrevations thereof
  126.   ;; b) a list of (a)
  127.   (let ((result (canonicalize-inst-pair inst-list specifier-type t)))
  128.     (if (not (eq result t))
  129.     ;; case (a)
  130.     (list result)
  131.  
  132.       (if (not (consp inst-list))
  133.       ;; not an inst-list.
  134.       (if noerror t
  135.        ;; this will signal an appropriate error.
  136.         (check-valid-instantiator inst-list specifier-type))
  137.  
  138.     ;; case (b)
  139.     (catch 'cann-inst-list
  140.       ;; don't use mapcar here; we need to catch the case of
  141.       ;; an invalid list.
  142.       (let ((rest inst-list)
  143.         (result nil))
  144.         (while rest
  145.           (if (not (consp rest))
  146.           (if noerror (throw 'cann-inst-list t)
  147.             (signal 'error (list "Invalid list format" inst-list)))
  148.         (let ((res2 (canonicalize-inst-pair (car rest) specifier-type
  149.                             noerror)))
  150.           (if (eq res2 t)
  151.               ;; at this point, we know we're noerror because
  152.               ;; otherwise canonicalize-inst-pair would have
  153.               ;; signalled an error.
  154.               (throw 'cann-inst-list t)
  155.             (setq result (cons res2 result)))))
  156.           (setq rest (cdr rest)))
  157.         (nreverse result)))))))
  158.  
  159. (defun canonicalize-spec (spec specifier-type &optional noerror)
  160.   "Canonicalize the given SPEC (a specification).
  161.  
  162. SPECIFIER-TYPE specifies the type of specifier that this SPEC-LIST
  163. will be used for.
  164.  
  165. Canonicalizing means converting to the full form for a spec, i.e.
  166. `(LOCALE (TAG-SET . INSTANTIATOR) ...)'.  This function accepts a
  167. possibly abbreviated inst-list or a cons of a locale and a possibly
  168. abbreviated inst-list. (See `canonicalize-inst-list'.)
  169.  
  170. If NOERROR is nil, signal an error if the specification is invalid;
  171. otherwise return t."
  172.   ;; OK, the possibilities are:
  173.   ;;
  174.   ;; a) an inst-list or some abbrevation thereof
  175.   ;; b) a cons of a locale and an inst-list
  176.   (let ((result (canonicalize-inst-list spec specifier-type t)))
  177.     (if (not (eq result t))
  178.     ;; case (a)
  179.     (cons 'global result)
  180.  
  181.       (if (not (consp spec))
  182.       ;; not a spec.
  183.       (if noerror t
  184.         ;; this will signal an appropriate error.
  185.         (check-valid-instantiator spec specifier-type))
  186.  
  187.     (if (not (valid-specifier-locale-p (car spec)))
  188.         ;; invalid locale.
  189.         (if noerror t
  190.           (signal 'error (list "Invalid specifier locale" (car spec))))
  191.  
  192.       ;; case (b)
  193.       (let ((result (canonicalize-inst-list (cdr spec) specifier-type
  194.                         noerror)))
  195.         (if (eq result t)
  196.         ;; at this point, we know we're noerror because
  197.         ;; otherwise canonicalize-inst-list would have
  198.         ;; signalled an error.
  199.         t
  200.           (cons (car spec) result))))))))
  201.  
  202. (defun canonicalize-spec-list (spec-list specifier-type &optional noerror)
  203.   "Canonicalize the given SPEC-LIST (a list of specifications).
  204.  
  205. SPECIFIER-TYPE specifies the type of specifier that this SPEC-LIST
  206. will be used for.
  207.  
  208. Canonicalizing means converting to the full form for a spec-list, i.e.
  209. `((LOCALE (TAG-SET . INSTANTIATOR) ...) ...)'.  This function accepts
  210. a possibly abbreviated specification or a list of such things. (See
  211. `canonicalize-spec'.) This is the function used to convert spec-lists
  212. accepted by `set-specifier' and such into a form suitable for
  213. `add-spec-list-to-specifier'.
  214.  
  215. This function tries extremely hard to resolve any ambiguities,
  216. and the built-in specifier types (font, image, toolbar, etc.) are
  217. designed so that there won't be any ambiguities.
  218.  
  219. If NOERROR is nil, signal an error if the spec-list is invalid;
  220. otherwise return t."
  221.   ;; OK, the possibilities are:
  222.   ;;
  223.   ;; a) a spec or various abbrevations thereof
  224.   ;; b) a list of (a)
  225.   (let ((result (canonicalize-spec spec-list specifier-type t)))
  226.     (if (not (eq result t))
  227.     ;; case (a)
  228.     (list result)
  229.  
  230.       (if (not (consp spec-list))
  231.       ;; not a spec-list.
  232.       (if noerror t
  233.        ;; this will signal an appropriate error.
  234.         (check-valid-instantiator spec-list specifier-type))
  235.  
  236.     ;; case (b)
  237.     (catch 'cann-spec-list
  238.       ;; don't use mapcar here; we need to catch the case of
  239.       ;; an invalid list.
  240.       (let ((rest spec-list)
  241.         (result nil))
  242.         (while rest
  243.           (if (not (consp rest))
  244.           (if noerror (throw 'cann-spec-list t)
  245.             (signal 'error (list "Invalid list format" spec-list)))
  246.         (let ((res2 (canonicalize-spec (car rest) specifier-type
  247.                            noerror)))
  248.           (if (eq res2 t)
  249.               ;; at this point, we know we're noerror because
  250.               ;; otherwise canonicalize-spec would have
  251.               ;; signalled an error.
  252.               (throw 'cann-spec-list t)
  253.             (setq result (cons res2 result)))))
  254.           (setq rest (cdr rest)))
  255.         (nreverse result)))))))
  256.  
  257. (defun set-specifier (specifier value &optional how-to-add)
  258.   "Add some specifications to SPECIFIER.
  259. VALUE can be a single instantiator or tagged instantiator (added as a
  260. global specification), a list of tagged and/or untagged instantiators
  261. (added as a global specification), a cons of a locale and instantiator
  262. or locale and instantiator list, a list of such conses, or nearly any
  263. other reasonable form.  More specifically, VALUE can be anything
  264. accepted by `canonicalize-spec-list'.
  265.  
  266. HOW-TO-ADD is the same as in `add-spec-to-specifier'.
  267.  
  268. Note that `set-specifier' is exactly complementary to `specifier-specs'
  269. except in the case where SPECIFIER has no specs at all in it but nil
  270. is a valid instantiator (in that case, `specifier-specs' will return
  271. nil (meaning no specs) and `set-specifier' will interpret the `nil'
  272. as meaning \"I'm adding a global instantiator and its value is `nil'\"),
  273. or in strange cases where there is an ambiguity between a spec-list\n\
  274. and an inst-list, etc. (The built-in specifier types are designed\n\
  275. in such a way as to avoid any such ambiguities.)
  276.  
  277. If you want to work with spec-lists, you should probably not use these
  278. functions, but should use the lower-level functions `specifier-spec-list'
  279. and `add-spec-list-to-specifier'.  These functions always work with
  280. fully-qualified spec-lists; thus, there is no possibility for
  281. ambiguity and no need to go through the function `canonicalize-spec-list',
  282. which is potentially time-consuming."
  283.   (add-spec-list-to-specifier
  284.     specifier
  285.     (canonicalize-spec-list value (specifier-type specifier))
  286.     how-to-add))
  287.