(MAKEIT.BAT): Modify for apel-ja@lists.chise.org.
[elisp/apel.git] / product.el
1 ;;; product.el --- Functions for product version information.
2
3 ;; Copyright (C) 1999,2000 Free Software Foundation, Inc.
4
5 ;; Author: Shuhei KOBAYASHI <shuhei@aqua.ocn.ne.jp>
6 ;;      Keiichi Suzuki <keiichi@nanap.org>
7 ;; Keywords: compatibility, User-Agent
8
9 ;; This file is part of APEL (A Portable Emacs Library).
10
11 ;; This program is free software; you can redistribute it and/or
12 ;; modify it under the terms of the GNU General Public License as
13 ;; published by the Free Software Foundation; either version 2, or (at
14 ;; your option) any later version.
15
16 ;; This program is distributed in the hope that it will be useful, but
17 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19 ;; General Public License for more details.
20
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with this program; see the file COPYING.  If not, write to
23 ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24 ;; Boston, MA 02110-1301, USA.
25
26 ;;; Commentary:
27
28 ;; This module defines some utility functions for product information,
29 ;; used for User-Agent header field.
30 ;;
31 ;; User-Agent header field first appeared in HTTP [RFC 1945, RFC 2616]
32 ;; and adopted to News Article Format draft [USEFOR].
33 ;;
34 ;; [RFC 1945] Hypertext Transfer Protocol -- HTTP/1.0.
35 ;;  T. Berners-Lee, R. Fielding & H. Frystyk. May 1996.
36 ;;
37 ;; [RFC 2616] Hypertext Transfer Protocol -- HTTP/1.1.
38 ;;  R. Fielding, J. Gettys, J. Mogul, H. Frystyk, L. Masinter, P. Leach,
39 ;;  T. Berners-Lee. June 1999.
40 ;;
41 ;; [USEFOR] News Article Format, <draft-ietf-usefor-article-02.txt>.
42 ;;  USEFOR Working Group. March 1999.
43
44 ;;; Code:
45
46 (defvar product-obarray (make-vector 13 0))
47
48 (defvar product-ignore-checkers nil)
49
50 (defun product-define (name &optional family version code-name)
51   "Define a product as a set of NAME, FAMILY, VERSION, and CODE-NAME.
52 NAME is a string.  Optional 2nd argument FAMILY is a string of
53 family product name.  Optional 3rd argument VERSION is a list of
54 numbers.  Optional 4th argument CODE-NAME is a string."
55   (and family
56        (product-add-to-family family name))
57   (set (intern name product-obarray)
58        (vector name family version code-name nil nil nil nil)))
59
60 (defun product-name (product)
61   "Return the name of PRODUCT, a string."
62   (aref product 0))
63 (defun product-family (product)
64   "Return the family name of PRODUCT, a string."
65   (aref product 1))
66 (defun product-version (product)
67   "Return the version of PRODUCT, a list of numbers."
68   (aref product 2))
69 (defun product-code-name (product)
70   "Return the code-name of PRODUCT, a string."
71   (aref product 3))
72 (defun product-checkers (product)
73   "Return the checkers of PRODUCT, a list of functions."
74   (aref product 4))
75 (defun product-family-products (product)
76   "Return the family products of PRODUCT, a list of strings."
77   (aref product 5))
78 (defun product-features (product)
79   "Return the features of PRODUCT, a list of feature."
80   (aref product 6))
81 (defun product-version-string (product)
82   "Return the version string of PRODUCT, a string."
83   (aref product 7))
84
85 (defun product-set-name (product name)
86   "Set name of PRODUCT to NAME."
87   (aset product 0 name))
88 (defun product-set-family (product family)
89   "Set family name of PRODUCT to FAMILY."
90   (aset product 1 family))
91 (defun product-set-version (product version)
92   "Set version of PRODUCT to VERSION."
93   (aset product 2 version))
94 ;; Some people want to translate code-name.
95 (defun product-set-code-name (product code-name)
96   "Set code-name of PRODUCT to CODE-NAME."
97   (aset product 3 code-name))
98 (defun product-set-checkers (product checkers)
99   "Set checker functions of PRODUCT to CHECKERS."
100   (aset product 4 checkers))
101 (defun product-set-family-products (product products)
102   "Set family products of PRODUCT to PRODUCTS."
103   (aset product 5 products))
104 (defun product-set-features (product features)
105   "Set features of PRODUCT to FEATURES."
106   (aset product 6 features))
107 (defun product-set-version-string (product version-string)
108   "Set version string of PRODUCT to VERSION-STRING."
109   (aset product 7 version-string))
110
111 (defun product-add-to-family (family product-name)
112   "Add a product to a family.
113 FAMILY is a product structure which returned by `product-define'.
114 PRODUCT-NAME is a string of the product's name ."
115   (let ((family-product (product-find-by-name family)))
116     (if family-product
117         (let ((dest (product-family-products family-product)))
118           (or (member product-name dest)
119               (product-set-family-products
120                family-product (cons product-name dest))))
121       (error "Family product `%s' is not defined" family))))
122
123 (defun product-remove-from-family (family product-name)
124   "Remove a product from a family.
125 FAMILY is a product string which returned by `product-define'.
126 PRODUCT-NAME is a string of the product's name."
127   (let ((family-product (product-find-by-name family)))
128     (if family-product
129         (product-set-family-products
130          family-product
131          (delete product-name (product-family-products family-product)))
132       (error "Family product `%s' is not defined" family))))
133
134 (defun product-add-checkers (product &rest checkers)
135   "Add checker function(s) to a product.
136 PRODUCT is a product structure which returned by `product-define'.
137 The rest arguments CHECKERS should be functions.  These functions
138 are registered to the product's checkers list, and will be called by
139  `product-run-checkers'.
140 If a checker is `ignore' will be ignored all checkers after this."
141   (setq product (product-find product))
142   (or product-ignore-checkers
143       (let ((dest (product-checkers product))
144             checker)
145         (while checkers
146           (setq checker (car checkers)
147                 checkers (cdr checkers))
148           (or (memq checker dest)
149               (setq dest (cons checker dest))))
150         (product-set-checkers product dest))))
151
152 (defun product-remove-checkers (product &rest checkers)
153   "Remove checker function(s) from a product.
154 PRODUCT is a product structure which returned by `product-define'.
155 The rest arguments CHECKERS should be functions.  These functions removed
156 from the product's checkers list."
157   (setq product (product-find product))
158   (let ((dest (product-checkers product)))
159     (while checkers
160       (setq checkers (cdr checkers)
161             dest (delq (car checkers) dest)))
162     (product-set-checkers product dest)))
163
164 (defun product-add-feature (product feature)
165   "Add a feature to the features list of a product.
166 PRODUCT is a product structure which returned by `product-define'.
167 FEATURE is a feature in the PRODUCT's."
168   (setq product (product-find product))
169   (let ((dest (product-features product)))
170     (or (memq feature dest)
171         (product-set-features product (cons feature dest)))))
172
173 (defun product-remove-feature (product feature)
174   "Remove a feature from the features list of a product.
175 PRODUCT is a product structure which returned by `product-define'.
176 FEATURE is a feature which registered in the products list of PRODUCT."
177   (setq product (product-find product))
178   (product-set-features product
179                         (delq feature (product-features product))))
180
181 (defun product-run-checkers (product version &optional force)
182   "Run checker functions of product.
183 PRODUCT is a product structure which returned by `product-define'.
184 VERSION is target version.
185 If optional 3rd argument FORCE is non-nil then do not ignore
186 all checkers."
187   (let ((checkers (product-checkers product)))
188     (if (or force
189             (not (memq 'ignore checkers)))
190         (let ((version (or version
191                            (product-version product))))
192           (while checkers
193             (funcall (car checkers) version version)
194             (setq checkers (cdr checkers)))))))
195
196 (defun product-find-by-name (name)
197   "Find product by name and return a product structure.
198 NAME is a string of the product's name."
199   (symbol-value (intern-soft name product-obarray)))
200
201 (defun product-find-by-feature (feature)
202   "Get a product structure of a feature's product.
203 FEATURE is a symbol of the feature."
204   (get feature 'product))
205
206 (defun product-find (product)
207   "Find product information.
208 If PRODUCT is a product structure, then return PRODUCT itself.
209 If PRODUCT is a string, then find product by name and return a
210 product structure.  If PRODUCT is symbol of feature, then return
211 the feature's product."
212   (cond
213    ((and (symbolp product)
214          (featurep product))
215     (product-find-by-feature product))
216    ((stringp product)
217     (product-find-by-name product))
218    ((vectorp product)
219     product)
220    (t
221     (error "Invalid product %s" product))))
222
223 (put 'product-provide 'lisp-indent-function 1)
224 (defmacro product-provide (feature-def product-def)
225   "Declare a feature as a part of product.
226 FEATURE-DEF is a definition of the feature.
227 PRODUCT-DEF is a definition of the product."
228   (let* ((feature feature-def)
229          (product (product-find (eval product-def)))
230          (product-name (product-name product))
231          (product-family (product-family product))
232          (product-version (product-version product))
233          (product-code-name (product-code-name product))
234          (product-version-string (product-version-string product)))
235     (` (progn
236          (, product-def)
237          (put (, feature) 'product
238               (let ((product (product-find-by-name (, product-name))))
239                 (product-run-checkers product '(, product-version))
240                 (and (, product-family)
241                      (product-add-to-family (, product-family)
242                                             (, product-name)))
243                 (product-add-feature product (, feature))
244                 (if (equal '(, product-version) (product-version product))
245                     product
246                   (vector (, product-name) (, product-family)
247                           '(, product-version) (, product-code-name)
248                           nil nil nil (, product-version-string)))))
249          (, feature-def)))))
250
251 (defun product-version-as-string (product)
252   "Return version number of product as a string.
253 PRODUCT is a product structure which returned by `product-define'.
254 If optional argument UPDATE is non-nil, then regenerate
255 `product-version-string' from `product-version'."
256   (setq product (product-find product))
257   (or (product-version-string product)
258       (and (product-version product)
259            (product-set-version-string product
260                                        (mapconcat (function int-to-string)
261                                                   (product-version product)
262                                                   ".")))))
263
264 (defun product-string-1 (product &optional verbose)
265   "Return information of product as a string of \"NAME/VERSION\".
266 PRODUCT is a product structure which returned by `product-define'.
267 If optional argument VERBOSE is non-nil, then return string of
268 \"NAME/VERSION (CODE-NAME)\"."
269   (setq product (product-find product))
270   (concat (product-name product)
271           (let ((version-string (product-version-as-string product)))
272             (and version-string
273                  (concat "/" version-string)))
274           (and verbose (product-code-name product)
275                (concat " (" (product-code-name product) ")"))))
276
277 (defun product-for-each (product all function &rest args)
278   "Apply a function to a product and the product's family with args.
279 PRODUCT is a product structure which returned by `product-define'.
280 If ALL is nil, apply function to only products which provided feature.
281 FUNCTION is a function.  The function called with following arguments.
282 The 1st argument is a product structure.  The rest arguments are ARGS."
283   (setq product (product-find product))
284   (let ((family (product-family-products product)))
285     (and (or all (product-features product))
286          (apply function product args))
287     (while family
288       (apply 'product-for-each (car family) all function args)
289       (setq family (cdr family)))))
290
291 (defun product-string (product)
292   "Return information of product as a string of \"NAME/VERSION\".
293 PRODUCT is a product structure which returned by `product-define'."
294   (let (dest)
295     (product-for-each product nil
296      (function
297       (lambda (product)
298         (let ((str (product-string-1 product nil)))
299           (if str
300               (setq dest (if dest
301                              (concat dest " " str)
302                            str)))))))
303     dest))
304
305 (defun product-string-verbose (product)
306   "Return information of product as a string of \"NAME/VERSION (CODE-NAME)\".
307 PRODUCT is a product structure which returned by `product-define'."
308   (let (dest)
309     (product-for-each product nil
310      (function
311       (lambda (product)
312         (let ((str (product-string-1 product t)))
313           (if str
314               (setq dest (if dest
315                              (concat dest " " str)
316                            str)))))))
317     dest))
318
319 (defun product-version-compare (v1 v2)
320   "Compare two versions.
321 Return an integer greater than, equal to, or less than 0,
322 according as the version V1 is greater than, equal to, or less
323 than the version V2.
324 Both V1 and V2 are a list of integer(s) respectively."
325   (while (and v1 v2 (= (car v1) (car v2)))
326     (setq v1 (cdr v1)
327           v2 (cdr v2)))
328   (if v1 (if v2 (- (car v1) (car v2)) 1) (if v2 -1 0)))
329
330 (defun product-version>= (product require-version)
331   "Compare product version with required version.
332 PRODUCT is a product structure which returned by `product-define'.
333 REQUIRE-VERSION is a list of integer."
334   (>= (product-version-compare (product-version (product-find product))
335                                require-version)
336       0))
337
338 (defun product-list-products ()
339   "List all products information."
340   (let (dest)
341     (mapatoms
342      (function
343       (lambda (sym)
344         (setq dest (cons (symbol-value sym) dest))))
345      product-obarray)
346     dest))
347
348 (defun product-parse-version-string (verstr)
349   "Parse version string \".*v1.v2... (CODE-NAME)\".
350 Return list of version, code-name, and version-string.
351 VERSTR is a string."
352   (let (version version-string code-name)
353     (and (string-match "\\(\\([0-9.]+\\)[^ ]*\\)[^(]*\\((\\(.+\\))\\)?" verstr)
354          (let ((temp (substring verstr (match-beginning 2) (match-end 2))))
355            (setq version-string (substring verstr
356                                            (match-beginning 1)
357                                            (match-end 1))
358                  code-name (and (match-beginning 4)
359                                 (substring verstr
360                                            (match-beginning 4)
361                                            (match-end 4))))
362            (while (string-match "^\\([0-9]+\\)\\.?" temp)
363              (setq version (cons (string-to-number
364                                   (substring temp
365                                              (match-beginning 1)
366                                              (match-end 1)))
367                                  version)
368                    temp (substring temp (match-end 0))))))
369     (list (nreverse version) code-name version-string)))
370
371
372 ;;; @ End.
373 ;;;
374
375 (provide 'product)                      ; beware of circular dependency.
376 (require 'apel-ver)                     ; these two files depend on each other.
377 (product-provide 'product 'apel-ver)
378 \f
379
380 ;;; @ Define emacs versions.
381 ;;;
382
383 (require 'pym)
384
385 (defconst-maybe emacs-major-version
386   (progn (string-match "^[0-9]+" emacs-version)
387          (string-to-int (substring emacs-version
388                                    (match-beginning 0)(match-end 0))))
389   "Major version number of this version of Emacs.")
390 (defconst-maybe emacs-minor-version
391   (progn (string-match "^[0-9]+\\.\\([0-9]+\\)" emacs-version)
392          (string-to-int (substring emacs-version
393                                    (match-beginning 1)(match-end 1))))
394   "Minor version number of this version of Emacs.")
395
396 ;;(or (product-find "emacs")
397 ;;    (progn
398 ;;      (product-define "emacs")
399 ;;      (cond
400 ;;       ((featurep 'meadow)
401 ;;      (let* ((info (product-parse-version-string (Meadow-version)))
402 ;;             (version (nth 0 info))
403 ;;             (code-name (nth 1 info))
404 ;;             (version-string (nth 2 info)))
405 ;;        (product-set-version-string
406 ;;         (product-define "Meadow" "emacs" version code-name)
407 ;;         version-string)
408 ;;        (product-provide 'Meadow "Meadow"))
409 ;;      (and (featurep 'mule)
410 ;;           (let* ((info (product-parse-version-string mule-version))
411 ;;                  (version (nth 0 info))
412 ;;                  (code-name (nth 1 info))
413 ;;                  (version-string (nth 2 info)))
414 ;;             (product-set-version-string
415 ;;              (product-define "MULE" "Meadow" version code-name)
416 ;;              version-string)
417 ;;             (product-provide 'mule "MULE")))
418 ;;      (let* ((info (product-parse-version-string emacs-version))
419 ;;             (version (nth 0 info))
420 ;;             (code-name (nth 1 info))
421 ;;             (version-string (nth 2 info)))
422 ;;        (product-set-version-string
423 ;;         (product-define "Emacs" "Meadow" version code-name)
424 ;;         version-string)
425 ;;        (product-provide 'emacs "Emacs")))
426 ;;       )))
427
428 ;;; product.el ends here