Package: emacs;
Reported by: michael_heerdegen <at> web.de
Date: Wed, 10 Apr 2013 20:32:01 UTC
Severity: normal
Tags: moreinfo
Found in version 24.3.50
Done: Lars Ingebrigtsen <larsi <at> gnus.org>
Bug is archived. No further changes may be made.
Message #11 received at 14175 <at> debbugs.gnu.org (full text, mbox):
From: Michael Heerdegen <michael_heerdegen <at> web.de> To: 14175 <at> debbugs.gnu.org Subject: Re: bug#14175: 24.3.50; Bad completion behavior with read-file-name-completion-ignore-case t Date: Fri, 12 Apr 2013 16:53:47 +0200
Michael Heerdegen <michael_heerdegen <at> web.de> writes: > Hello, > > 1. I tried to debug a bit. > > When you hit TAB the second time, this call in > `completion--nth-completion' changes the result from ("download/" > "Downloads/") to ("Download/" "Downloads/"): > > (if requote > (funcall requote result n) > result) Some more information: this call at the very last lines of `completion-table-with-quoting': (when last (setcdr last nil) (completion--twq-all string ustring unquoted-result base unquote requote)) returns the changed case of the first candidate (from "~/download" to "~/Download"), i.e., introduces the error. Here is a backtrace of that point of time: ,---------------------------------------------------------------------- | completion--twq-all("~/Download" "~/Download" (#("download/" 0 8 (face (completions-common-part)) 8 9 (face (completions-first-difference))) #("Downloads/" 0 8 (face (completions-common-part)) 8 9 (face (completions-first-difference)))) 2 substitute-in-file-name completion--sifn-requote) | (progn (setcdr last nil) (completion--twq-all string ustring unquoted-result base unquote requote)) | (if last (progn (setcdr last nil) (completion--twq-all string ustring unquoted-result base unquote requote))) | (let* ((last (last unquoted-result)) (base (or (cdr last) 0))) (if last (progn (setcdr last nil) (completion--twq-all string ustring unquoted-result base unquote requote)))) | (let nil (debug) (let* ((last (last unquoted-result)) (base (or (cdr last) 0))) (if last (progn (setcdr last nil) (completion--twq-all string ustring unquoted-result base unquote requote))))) | (cond ((eq op (quote 1)) (let nil (if (not (stringp (car-safe unquoted-result))) unquoted-result (completion--twq-try string ustring (car unquoted-result) (cdr unquoted-result) unquote requote)))) ((eq op (quote 2)) (let nil (debug) (let* ((last (last unquoted-result)) (base (or (cdr last) 0))) (if last (progn (setcdr last nil) (completion--twq-all string ustring unquoted-result base unquote requote)))))) (t nil)) | (closure ((uprefix . "~/Download") (ustring . #1="~/Download") (action . completion--unquote) (pred . 10) (string . #1#) (requote . completion--sifn-requote) (unquote . substitute-in-file-name) (table . completion-file-name-table) t) (unquoted-result op) (cond ((eq op (quote 1)) (let nil (if (not (stringp (car-safe unquoted-result))) unquoted-result (completion--twq-try string ustring (car unquoted-result) (cdr unquoted-result) unquote requote)))) ((eq op (quote 2)) (let nil (debug) (let* ((last (last unquoted-result)) (base (or ... 0))) (if last (progn (setcdr last nil) (completion--twq-all string ustring unquoted-result base unquote requote)))))) (t nil)))((#("download/" 0 8 (face (completions-common-part)) 8 9 (face (completions-first-difference))) #("Downloads/" 0 8 (face (completions-common-part)) 8 9 (face (completions-first-difference)))) 2) | funcall((closure ((uprefix . "~/Download") (ustring . #1="~/Download") (action . completion--unquote) (pred . 10) (string . #1#) (requote . completion--sifn-requote) (unquote . substitute-in-file-name) (table . completion-file-name-table) t) (unquoted-result op) (cond ((eq op (quote 1)) (let nil (if (not (stringp (car-safe unquoted-result))) unquoted-result (completion--twq-try string ustring (car unquoted-result) (cdr unquoted-result) unquote requote)))) ((eq op (quote 2)) (let nil (debug) (let* ((last (last unquoted-result)) (base (or ... 0))) (if last (progn (setcdr last nil) (completion--twq-all string ustring unquoted-result base unquote requote)))))) (t nil))) (#("download/" 0 8 (face (completions-common-part)) 8 9 (face (completions-first-difference))) #("Downloads/" 0 8 (face (completions-common-part)) 8 9 (face (completions-first-difference)))) 2) | (if requote (funcall requote result n) result) | (let ((requote (if (completion-metadata-get metadata (quote completion--unquote-requote)) (progn (let ((new ...)) (setq string (car ...)) (setq table (car ...)) (setq point (car ...)) (car (prog1 new ...)))))) (result (progn (completion--some (function (lambda (style) (funcall ... string table pred point))) (completion--styles metadata))))) (if requote (funcall requote result n) result)) | completion--nth-completion(2 "~/Download" read-file-name-internal file-exists-p 10 (metadata (category . file) (completion--unquote-requote . t))) | completion-all-completions("~/Download" read-file-name-internal file-exists-p 10 (metadata (category . file) (completion--unquote-requote . t))) | (let* ((start (field-beginning)) (end (field-end)) (string (field-string)) (md (completion--field-metadata start)) (completions (completion-all-completions string minibuffer-completion-table minibuffer-completion-predicate (- (point) (field-beginning)) md))) (message nil) (if (or (null completions) (and (not (consp (cdr completions))) (equal (car completions) string))) (progn (minibuffer-hide-completions) (ding) (minibuffer-message (if completions "Sole completion" "No completions"))) (let* ((last (last completions)) (base-size (cdr last)) (prefix (if (zerop base-size) nil (substring string 0 base-size))) (all-md (completion--metadata (buffer-substring-no-properties start (point)) base-size md minibuffer-completion-table minibuffer-completion-predicate)) (afun (or (completion-metadata-get all-md (quote annotation-function)) (plist-get completion-extra-properties :annotation-function) completion-annotate-function)) (display-buffer-mark-dedicated (quote soft))) (let* ((#1=#:old-dir default-directory) (#4=#:buf (save-current-buffer (set-buffer ...) (prog1 ... ... ... ... ... ... ...))) (standard-output #4#)) (prog1 (progn (if last (progn ...)) (setq completions (let ... ...)) (if afun (progn ...)) (save-current-buffer (set-buffer standard-output) (set ... ...) (set ... ...)) (display-completion-list completions)) (internal-temp-output-buffer-show #4#))))) nil) | minibuffer-completion-help() | (if (if (eq completion-auto-help (quote lazy)) (let nil (eq this-command last-command)) (let nil completion-auto-help)) (minibuffer-completion-help) (completion--message "Next char not unique")) | (cond ((and (consp (cdr comps)) (not (condition-case nil (progn (consp (nthcdr threshold comps))) (error nil)))) (setq completed t exact t) (completion--cache-all-sorted-completions comps) (minibuffer-force-complete)) (completed (minibuffer-hide-completions) (if exact (completion--done completion (if (< comp-pos (length completion)) (quote exact) (quote unknown))))) ((not exact) (if (if (eq completion-auto-help (quote lazy)) (let nil (eq this-command last-command)) (let nil completion-auto-help)) (minibuffer-completion-help) (completion--message "Next char not unique"))) (t (if (and (eq this-command last-command) completion-auto-help) (minibuffer-completion-help)) (completion--done completion (quote exact) (if expect-exact nil "Complete, but not unique")))) | (let* ((exact (test-completion completion minibuffer-completion-table minibuffer-completion-predicate)) (threshold (completion--cycle-threshold md)) (comps (if (and threshold (or (not completed) (< (car ...) comp-pos))) (progn (completion-all-sorted-completions))))) (completion--flush-all-sorted-completions) (cond ((and (consp (cdr comps)) (not (condition-case nil (progn (consp ...)) (error nil)))) (setq completed t exact t) (completion--cache-all-sorted-completions comps) (minibuffer-force-complete)) (completed (minibuffer-hide-completions) (if exact (completion--done completion (if (< comp-pos (length completion)) (quote exact) (quote unknown))))) ((not exact) (if (if (eq completion-auto-help (quote lazy)) (let nil (eq this-command last-command)) (let nil completion-auto-help)) (minibuffer-completion-help) (completion--message "Next char not unique"))) (t (if (and (eq this-command last-command) completion-auto-help) (minibuffer-completion-help)) (completion--done completion (quote exact) (if expect-exact nil "Complete, but not unique")))) (minibuffer--bitset completed t exact)) | (if (not (or unchanged completed)) (completion--do-completion try-completion-function expect-exact) (let* ((exact (test-completion completion minibuffer-completion-table minibuffer-completion-predicate)) (threshold (completion--cycle-threshold md)) (comps (if (and threshold (or (not completed) (< ... comp-pos))) (progn (completion-all-sorted-completions))))) (completion--flush-all-sorted-completions) (cond ((and (consp (cdr comps)) (not (condition-case nil (progn ...) (error nil)))) (setq completed t exact t) (completion--cache-all-sorted-completions comps) (minibuffer-force-complete)) (completed (minibuffer-hide-completions) (if exact (completion--done completion (if (< comp-pos ...) (quote exact) (quote unknown))))) ((not exact) (if (if (eq completion-auto-help (quote lazy)) (let nil (eq this-command last-command)) (let nil completion-auto-help)) (minibuffer-completion-help) (completion--message "Next char not unique"))) (t (if (and (eq this-command last-command) completion-auto-help) (minibuffer-completion-help)) (completion--done completion (quote exact) (if expect-exact nil "Complete, but not unique")))) (minibuffer--bitset completed t exact))) | (let* ((comp-pos (cdr comp)) (completion (car comp)) (completed (not (eq t (compare-strings completion nil nil string nil nil t)))) (unchanged (eq t (compare-strings completion nil nil string nil nil nil)))) (if unchanged (goto-char end) (completion--replace beg end completion)) (forward-char (- comp-pos (length completion))) (if (not (or unchanged completed)) (completion--do-completion try-completion-function expect-exact) (let* ((exact (test-completion completion minibuffer-completion-table minibuffer-completion-predicate)) (threshold (completion--cycle-threshold md)) (comps (if (and threshold (or ... ...)) (progn (completion-all-sorted-completions))))) (completion--flush-all-sorted-completions) (cond ((and (consp (cdr comps)) (not (condition-case nil ... ...))) (setq completed t exact t) (completion--cache-all-sorted-completions comps) (minibuffer-force-complete)) (completed (minibuffer-hide-completions) (if exact (completion--done completion (if ... ... ...)))) ((not exact) (if (if (eq completion-auto-help ...) (let nil ...) (let nil completion-auto-help)) (minibuffer-completion-help) (completion--message "Next char not unique"))) (t (if (and (eq this-command last-command) completion-auto-help) (minibuffer-completion-help)) (completion--done completion (quote exact) (if expect-exact nil "Complete, but not unique")))) (minibuffer--bitset completed t exact)))) | (cond ((null comp) (minibuffer-hide-completions) (if completion-fail-discreetly nil (ding) (completion--message "No match")) (minibuffer--bitset nil nil nil)) ((eq t comp) (minibuffer-hide-completions) (goto-char end) (completion--done string (quote finished) (if expect-exact nil "Sole completion")) (minibuffer--bitset nil nil t)) (t (let* ((comp-pos (cdr comp)) (completion (car comp)) (completed (not (eq t (compare-strings completion nil nil string nil nil t)))) (unchanged (eq t (compare-strings completion nil nil string nil nil nil)))) (if unchanged (goto-char end) (completion--replace beg end completion)) (forward-char (- comp-pos (length completion))) (if (not (or unchanged completed)) (completion--do-completion try-completion-function expect-exact) (let* ((exact (test-completion completion minibuffer-completion-table minibuffer-completion-predicate)) (threshold (completion--cycle-threshold md)) (comps (if ... ...))) (completion--flush-all-sorted-completions) (cond ((and ... ...) (setq completed t exact t) (completion--cache-all-sorted-completions comps) (minibuffer-force-complete)) (completed (minibuffer-hide-completions) (if exact ...)) ((not exact) (if ... ... ...)) (t (if ... ...) (completion--done completion ... ...))) (minibuffer--bitset completed t exact)))))) | (let* ((beg (field-beginning)) (end (field-end)) (string (buffer-substring beg end)) (md (completion--field-metadata beg)) (comp (funcall (or try-completion-function (quote completion-try-completion)) string minibuffer-completion-table minibuffer-completion-predicate (- (point) beg) md))) (cond ((null comp) (minibuffer-hide-completions) (if completion-fail-discreetly nil (ding) (completion--message "No match")) (minibuffer--bitset nil nil nil)) ((eq t comp) (minibuffer-hide-completions) (goto-char end) (completion--done string (quote finished) (if expect-exact nil "Sole completion")) (minibuffer--bitset nil nil t)) (t (let* ((comp-pos (cdr comp)) (completion (car comp)) (completed (not (eq t ...))) (unchanged (eq t (compare-strings completion nil nil string nil nil nil)))) (if unchanged (goto-char end) (completion--replace beg end completion)) (forward-char (- comp-pos (length completion))) (if (not (or unchanged completed)) (completion--do-completion try-completion-function expect-exact) (let* ((exact ...) (threshold ...) (comps ...)) (completion--flush-all-sorted-completions) (cond (... ... ... ...) (completed ... ...) (... ...) (t ... ...)) (minibuffer--bitset completed t exact))))))) | completion--do-completion() | (let* ((#1=#:val (completion--do-completion))) (if (eq #1# (quote 0)) (let nil nil) (let nil t))) | (cond ((window-live-p minibuffer-scroll-window) (let ((window minibuffer-scroll-window)) (save-current-buffer (set-buffer (window-buffer window)) (if (pos-visible-in-window-p (point-max) window) (set-window-start window (point-min) nil) (scroll-other-window)) nil))) ((and completion-cycling completion-all-sorted-completions) (minibuffer-force-complete) t) (t (let* ((#1=#:val (completion--do-completion))) (if (eq #1# (quote 0)) (let nil nil) (let nil t))))) | minibuffer-complete() | call-interactively(minibuffer-complete nil nil) | command-execute(minibuffer-complete) | read-from-minibuffer("Dired (directory): " "~/today/" (keymap (keymap (32)) keymap (7 . minibuffer-keyboard-quit) (menu-bar keymap (minibuf #1="Minibuf" keymap (tab menu-item "Complete" minibuffer-complete :help "Complete as far as possible") (space menu-item "Complete Word" minibuffer-complete-word :help "Complete at most one word") (63 menu-item "List Completions" minibuffer-completion-help :help "Display all possible completions") #1#)) (27 keymap (21) (23) (118 . switch-to-completions)) (prior . switch-to-completions) (63 . minibuffer-completion-help) (32 . minibuffer-complete-word) (9 . minibuffer-complete) keymap (f9 . my-enlarge-mb) (menu-bar keymap (minibuf #1# keymap (previous menu-item "Previous History Item" previous-history-element :help "Put previous minibuffer history element in the minibuffer") (next menu-item "Next History Item" next-history-element :help "Put next minibuffer history element in the minibuffer") (isearch-backward menu-item "Isearch History Backward" isearch-backward :help "Incrementally search minibuffer history backward") (isearch-forward menu-item "Isearch History Forward" isearch-forward :help "Incrementally search minibuffer history forward") (return menu-item "Enter" exit-minibuffer :key-sequence "" :help "Terminate input and exit minibuffer") (quit menu-item "Quit" abort-recursive-edit :help "Abort input and exit minibuffer") #1#)) (10 . exit-minibuffer) (13 . exit-minibuffer) (7 . abort-recursive-edit) (C-tab . file-cache-minibuffer-complete) (9 . self-insert-command) (XF86Back . previous-history-element) (up . previous-history-element) (prior . previous-history-element) (XF86Forward . next-history-element) (down . next-history-element) (next . next-history-element) (27 keymap (114 . previous-matching-history-element) (115 . next-matching-history-element) (112 . previous-history-element) (110 . next-history-element))) nil file-name-history "~/today/" nil) | (let* ((minibuffer-completion-table collection) (minibuffer-completion-predicate predicate) (minibuffer-completion-confirm (if (eq require-match t) nil require-match)) (base-keymap (if require-match minibuffer-local-must-match-map minibuffer-local-completion-map)) (keymap (if (memq minibuffer-completing-file-name (quote (nil lambda))) base-keymap (make-composed-keymap minibuffer-local-filename-completion-map base-keymap))) (result (read-from-minibuffer prompt initial-input keymap nil hist def inherit-input-method))) (if (and (equal result "") def) (progn (setq result (if (consp def) (car def) def)))) result) | completing-read-default("Dired (directory): " read-file-name-internal file-exists-p nil "~/today/" file-name-history "~/today/" nil) | completing-read("Dired (directory): " read-file-name-internal file-exists-p nil "~/today/" file-name-history "~/today/") | (progn (add-hook (quote minibuffer-setup-hook) #:setup-hook) (completing-read prompt (quote read-file-name-internal) pred mustmatch insdef (quote file-name-history) default-filename)) | (unwind-protect (progn (add-hook #1=(quote minibuffer-setup-hook) #2=#:setup-hook) (completing-read prompt (quote read-file-name-internal) pred mustmatch insdef (quote file-name-history) default-filename)) (remove-hook #1# #2#)) | (let (#1=#:setup-hook) (setq #1# (function (lambda nil (remove-hook #2=(quote minibuffer-setup-hook) #1#) (funcall (function (lambda nil (setq default-directory dir) (if ... ...) (set ... ...) (set-syntax-table minibuffer-local-filename-syntax))))))) (unwind-protect (progn (add-hook #2# #1#) (completing-read prompt (quote read-file-name-internal) pred mustmatch insdef (quote file-name-history) default-filename)) (remove-hook #2# #1#))) | (let ((dir (file-name-as-directory (expand-file-name dir)))) (let (#1=#:setup-hook) (setq #1# (function (lambda nil (remove-hook #2=(quote minibuffer-setup-hook) #1#) (funcall (function (lambda nil ... ... ... ...)))))) (unwind-protect (progn (add-hook #2# #1#) (completing-read prompt (quote read-file-name-internal) pred mustmatch insdef (quote file-name-history) default-filename)) (remove-hook #2# #1#)))) | (if (or (not (next-read-file-uses-dialog-p)) (file-remote-p dir)) (let ((dir (file-name-as-directory (expand-file-name dir)))) (let (#1=#:setup-hook) (setq #1# (function (lambda nil (remove-hook #2=(quote minibuffer-setup-hook) #1#) (funcall (function ...))))) (unwind-protect (progn (add-hook #2# #1#) (completing-read prompt (quote read-file-name-internal) pred mustmatch insdef (quote file-name-history) default-filename)) (remove-hook #2# #1#)))) (let ((file (file-name-nondirectory dir)) (dialog-mustmatch (not (memq mustmatch (quote (nil confirm confirm-after-completion)))))) (if (and (not default-filename) (not (zerop (length file)))) (progn (setq default-filename file) (setq dir (file-name-directory dir)))) (if default-filename (progn (setq default-filename (expand-file-name (if (consp default-filename) (car default-filename) default-filename) dir)))) (setq add-to-history t) (x-file-dialog prompt dir default-filename dialog-mustmatch (eq predicate (quote file-directory-p))))) | (let* ((val (if (or (not (next-read-file-uses-dialog-p)) (file-remote-p dir)) (let ((dir (file-name-as-directory ...))) (let (#1=#:setup-hook) (setq #1# (function ...)) (unwind-protect (progn ... ...) (remove-hook #2=... #1#)))) (let ((file (file-name-nondirectory dir)) (dialog-mustmatch (not ...))) (if (and (not default-filename) (not ...)) (progn (setq default-filename file) (setq dir ...))) (if default-filename (progn (setq default-filename ...))) (setq add-to-history t) (x-file-dialog prompt dir default-filename dialog-mustmatch (eq predicate (quote file-directory-p)))))) (replace-in-history (eq (car-safe file-name-history) val))) (if (consp default-filename) (progn (setq default-filename (car default-filename)))) (if (eq val default-filename) (progn (if (not replace-in-history) (setq add-to-history t)) (setq val ""))) (if val nil (error "No file name specified")) (if (and default-filename (string-equal val (if (consp insdef) (car insdef) insdef))) (setq val default-filename)) (setq val (substitute-in-file-name val)) (if replace-in-history (let ((val1 (minibuffer--double-dollars val))) (if history-delete-duplicates (setcdr file-name-history (delete val1 (cdr file-name-history)))) (if (string= val1 (cadr file-name-history)) (car (prog1 file-name-history (setq file-name-history (cdr file-name-history)))) (setcar file-name-history val1))) (if add-to-history (let ((val1 (minibuffer--double-dollars val))) (if (and (consp file-name-history) (equal (car file-name-history) val1)) nil (setq file-name-history (cons val1 (if history-delete-duplicates ... file-name-history))))))) val) | (let ((completion-ignore-case read-file-name-completion-ignore-case) (minibuffer-completing-file-name t) (pred (or predicate (quote file-exists-p))) (add-to-history nil)) (let* ((val (if (or (not (next-read-file-uses-dialog-p)) (file-remote-p dir)) (let ((dir ...)) (let (#1=#:setup-hook) (setq #1# ...) (unwind-protect ... ...))) (let ((file ...) (dialog-mustmatch ...)) (if (and ... ...) (progn ... ...)) (if default-filename (progn ...)) (setq add-to-history t) (x-file-dialog prompt dir default-filename dialog-mustmatch (eq predicate ...))))) (replace-in-history (eq (car-safe file-name-history) val))) (if (consp default-filename) (progn (setq default-filename (car default-filename)))) (if (eq val default-filename) (progn (if (not replace-in-history) (setq add-to-history t)) (setq val ""))) (if val nil (error "No file name specified")) (if (and default-filename (string-equal val (if (consp insdef) (car insdef) insdef))) (setq val default-filename)) (setq val (substitute-in-file-name val)) (if replace-in-history (let ((val1 (minibuffer--double-dollars val))) (if history-delete-duplicates (setcdr file-name-history (delete val1 (cdr file-name-history)))) (if (string= val1 (cadr file-name-history)) (car (prog1 file-name-history (setq file-name-history ...))) (setcar file-name-history val1))) (if add-to-history (let ((val1 (minibuffer--double-dollars val))) (if (and (consp file-name-history) (equal ... val1)) nil (setq file-name-history (cons val1 ...)))))) val)) | (let ((insdef (cond ((and insert-default-directory (stringp dir)) (if initial (cons (minibuffer--double-dollars ...) (length ...)) (minibuffer--double-dollars dir))) (initial (cons (minibuffer--double-dollars initial) 0))))) (let ((completion-ignore-case read-file-name-completion-ignore-case) (minibuffer-completing-file-name t) (pred (or predicate (quote file-exists-p))) (add-to-history nil)) (let* ((val (if (or (not ...) (file-remote-p dir)) (let (...) (let ... ... ...)) (let (... ...) (if ... ...) (if default-filename ...) (setq add-to-history t) (x-file-dialog prompt dir default-filename dialog-mustmatch ...)))) (replace-in-history (eq (car-safe file-name-history) val))) (if (consp default-filename) (progn (setq default-filename (car default-filename)))) (if (eq val default-filename) (progn (if (not replace-in-history) (setq add-to-history t)) (setq val ""))) (if val nil (error "No file name specified")) (if (and default-filename (string-equal val (if (consp insdef) (car insdef) insdef))) (setq val default-filename)) (setq val (substitute-in-file-name val)) (if replace-in-history (let ((val1 (minibuffer--double-dollars val))) (if history-delete-duplicates (setcdr file-name-history (delete val1 ...))) (if (string= val1 (cadr file-name-history)) (car (prog1 file-name-history ...)) (setcar file-name-history val1))) (if add-to-history (let ((val1 ...)) (if (and ... ...) nil (setq file-name-history ...))))) val))) | read-file-name-default("Dired (directory): " nil "/home/micha/today/" nil nil nil) | funcall(read-file-name-default "Dired (directory): " nil "/home/micha/today/" nil nil nil) | read-file-name("Dired (directory): " nil "/home/micha/today/" nil) | dired-read-dir-and-switches("") | call-interactively(dired nil nil) | command-execute(dired) `---------------------------------------------------------------------- I can reproduce this behavior manually: (completion--twq-all #1="~/Download" #1# '(#("download/" 0 8 (face (completions-common-part)) 8 9 (face (completions-first-difference))) #("Downloads/" 0 8 (face (completions-common-part)) 8 9 (face (completions-first-difference)))) 2 'substitute-in-file-name 'completion--sifn-requote) ==> (#("Download/" 0 8 (face completions-common-part) 8 9 (face (completions-first-difference))) #("Downloads/" 0 8 (face completions-common-part) 8 9 (face (completions-first-difference))) . 2) I can't dig further 'cause I don't know what `completion--twq-all' is or should do. HTH, Michael.
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.