Mercurial > emacs
changeset 53339:09ea561dfa8c
Merged in changes from CVS HEAD
Patches applied:
* miles@gnu.org--gnu-2004/emacs--cvs-trunk--0--patch-1
Update from CVS
* miles@gnu.org--gnu-2004/emacs--cvs-trunk--0--patch-2
Update from CVS
* miles@gnu.org--gnu-2004/emacs--cvs-trunk--0--patch-3
Update from CVS
git-archimport-id: lorentey@elte.hu--2004/emacs--multi-tty--0--patch-17
author | Karoly Lorentey <lorentey@elte.hu> |
---|---|
date | Sun, 28 Dec 2003 16:05:28 +0000 |
parents | 49084d566b9f (current diff) 25ce3b9f2836 (diff) |
children | db645482d6bc |
files | lib-src/rcs2log lisp/ChangeLog src/Makefile.in src/dispextern.h src/dispnew.c src/keyboard.c src/lisp.h src/macterm.c src/w32term.c src/xdisp.c src/xfaces.c src/xfns.c src/xterm.c |
diffstat | 46 files changed, 8295 insertions(+), 377 deletions(-) [+] |
line wrap: on
line diff
--- a/etc/NEWS Sun Dec 28 16:04:37 2003 +0000 +++ b/etc/NEWS Sun Dec 28 16:05:28 2003 +0000 @@ -1740,6 +1740,40 @@ whose cdr is the overlay in which the property was found, or nil if it was found as a text property or not found at all. +** The mouse pointer shape in void text areas (i.e. after the end of a +line or below the last line in the buffer) of the text window is now +controlled by the new variable `void-text-area-pointer'. The default +is to use the `arrow' (non-text) pointer. Other choices are `text' +(or nil), `hand', `vdrag', `hdrag', `modeline', and `hourglass'. + +** The mouse pointer shape over an image can now be controlled by the +:pointer image property. + +** The mouse pointer shape over ordinary text or images may now be +controlled/overriden via the `pointer' text property. + +** Images may now have an associated image map via the :map property. + +An image map is an alist where each element has the format (AREA ID PLIST). +An AREA is specified as either a rectangle, a circle, or a polygon: +A rectangle is a cons (rect . ((x0 . y0) . (x1 . y1))) specifying the +pixel coordinates of the upper left and bottom right corners. +A circle is a cons (circle . ((x0 . y0) . r)) specifying the center +and the radius of the circle; r may be a float or integer. +A polygon is a cons (poly . [x0 y0 x1 y1 ...]) where each pair in the +vector describes one corner in the polygon. + +When the mouse pointer is above a hot-spot area of an image, the +PLIST of that hot-spot is consulted; if it contains a `help-echo' +property it defines a tool-tip for the hot-spot, and if it contains +a `pointer' property, it defines the shape of the mouse cursor when +it is over the hot-spot. See the variable 'void-area-text-pointer' +for possible pointer shapes. + +When you click the mouse when the mouse pointer is over a hot-spot, +an event is composed by combining the ID of the hot-spot with the +mouse event, e.g. [area4 mouse-1] if the hot-spot's ID is `area4'. + ** Mouse event enhancements: *** Mouse clicks on fringes now generates left-fringe or right-fringes
--- a/lib-src/ChangeLog Sun Dec 28 16:04:37 2003 +0000 +++ b/lib-src/ChangeLog Sun Dec 28 16:05:28 2003 +0000 @@ -1,3 +1,11 @@ +2003-12-27 Paul Eggert <eggert@twinsun.com> + + * rcs2log (rlog_options): Append -rbranchtag if CVS/Tag indicates + a tag, and if the user has not specified an rlog option. + Adapted from a suggestion by Martin Stjernholm in + <http://mail.gnu.org/archive/html/bug-gnu-emacs/2003-07/msg00066.html>. + (Copyright): Update to 2003. + 2003-12-24 Thien-Thi Nguyen <ttn@gnu.org> * make-docfile.c (main): For return code, no longer special-case VMS. @@ -5461,7 +5469,7 @@ ;; coding: iso-2022-7bit ;; End: - Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2001, 2002 + Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2001, 2002, 2003 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted provided the copyright notice and this notice are preserved.
--- a/lib-src/rcs2log Sun Dec 28 16:04:37 2003 +0000 +++ b/lib-src/rcs2log Sun Dec 28 16:05:28 2003 +0000 @@ -29,9 +29,9 @@ Report bugs to <bug-gnu-emacs@gnu.org>.' -Id='$Id: rcs2log,v 1.51 2003/09/01 15:45:03 miles Exp $' +Id='$Id: rcs2log,v 1.52 2003/12/27 08:18:08 uid65632 Exp $' -# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 2001, 2002 +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 2001, 2002, 2003 # Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify @@ -49,7 +49,7 @@ # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. -Copyright='Copyright (C) 2002 Free Software Foundation, Inc. +Copyright='Copyright (C) 2003 Free Software Foundation, Inc. This program comes with NO WARRANTY, to the extent permitted by law. You may redistribute copies of this program under the terms of the GNU General Public License. @@ -195,8 +195,9 @@ # If no rlog options are given, # log the revisions checked in since the first ChangeLog entry. - # Since ChangeLog is only by date, some of these revisions may be duplicates of - # what's already in ChangeLog; it's the user's responsibility to remove them. + # Since ChangeLog is only by date, some of these revisions may be + # duplicates of what's already in ChangeLog; it's the user's + # responsibility to remove them. case $rlog_options in '') if test -s "$changelog" @@ -281,6 +282,21 @@ esac done + # If no rlog options are given, and if we are in a tagged CVS branch, + # log only the changes in that branch. + case $rlog_options in + '') + if test -f CVS/Tag + then + CVSTAG=`cat <CVS/Tag` || exit + case $CVSTAG in + T?*) + rlog_options=-r`expr "$CVSTAG" : 'T\(.*\)'`;; + *) + echo >&2 "$0: invalid CVS/Tag"; exit 1;; + esac + fi;; + esac fi # Use $rlog's -zLT option, if $rlog supports it.
--- a/lisp/ChangeLog Sun Dec 28 16:04:37 2003 +0000 +++ b/lisp/ChangeLog Sun Dec 28 16:05:28 2003 +0000 @@ -1,3 +1,34 @@ +2003-12-27 Kim F. Storm <storm@cua.dk> + + * ido.el: Handle non-readable directories. + (ido-decorations): Add 9th element for non-readable directory. + (ido-directory-nonreadable): New dynamic var. + (ido-set-current-directory): Set it. + (ido-read-buffer, ido-file-internal): + (ido-read-file-name, ido-read-directory-name): Let-bind it. + (ido-file-name-all-completions1): Return empty list for + non-readable directory. + (ido-exhibit): Print [Not readable] if directory is not readable. + (ido-expand-directory): New defun (based on tiny fix from Karl Chen). + (ido-read-file-name, ido-file-internal, ido-read-directory-name): + Use it. + +2003-12-27 Lars Hansen <larsh@math.ku.dk> + + * ls-lisp.el (ls-lisp-insert-directory): Add parameter 'string in + calls to directory-files-and-attributes and file-attributes. + (ls-lisp-format): Remove system dependent handling of user and + group id's. + +2003-12-25 Luc Teirlinck <teirllm@auburn.edu> + + * ffap.el (ffap-read-file-or-url): Revert previous change. + +2003-12-25 Andreas Schwab <schwab@suse.de> + + * jka-compr.el (jka-compr-insert-file-contents): Avoid error when + file not found. + 2003-12-08 Miles Bader <miles@gnu.org> * dired.el (dired-between-files): Always use dired-move-to-filename, @@ -67,6 +98,23 @@ * info.el (Info-unescape-quotes, Info-split-parameter-string) (Info-goto-emacs-command-node): Doc fixes. +2003-12-12 Jesper Harder <harder@ifa.au.dk> + + * cus-edit.el (custom-add-parent-links): Define "many". + +2003-12-08 Per Abrahamsen <abraham@dina.kvl.dk> + + * wid-edit.el (widget-child-value-get, widget-child-value-inline) + (widget-child-validate, widget-type-value-create) + (widget-type-default-get, widget-type-match): New functions. + (lazy): New widget. + (menu-choice, checklist, radio-button-choice, editable-list) + (group, documentation-string): Removed redundant (per 2003-10-25 + change) calls to `widget-children-value-delete'. + (widget-choice-value-get, widget-choice-value-inline): Removed + functions. + (menu-choice): Updated widget. + 2003-12-03 Kenichi Handa <handa@m17n.org> * language/cyrillic.el: Register "microsoft-cp1251" in
--- a/lisp/cus-edit.el Sun Dec 28 16:04:37 2003 +0000 +++ b/lisp/cus-edit.el Sun Dec 28 16:05:28 2003 +0000 @@ -1970,7 +1970,8 @@ (setq parents (cons symbol parents)))))) (and (null (get symbol 'custom-links)) ;No links of its own. (= (length parents) 1) ;A single parent. - (let ((links (get (car parents) 'custom-links))) + (let* ((links (get (car parents) 'custom-links)) + (many (> (length links) 2))) (when links (insert "\nParent documentation: ") (while links
--- a/lisp/ffap.el Sun Dec 28 16:04:37 2003 +0000 +++ b/lisp/ffap.el Sun Dec 28 16:05:28 2003 +0000 @@ -1216,7 +1216,7 @@ 'ffap-read-file-or-url-internal dir nil - (if dir (cons guess (1+ (length dir))) guess) + (if dir (cons guess (length dir)) guess) (list 'file-name-history)))) ;; Do file substitution like (interactive "F"), suggested by MCOOK. (or (ffap-url-p guess) (setq guess (substitute-in-file-name guess)))
--- a/lisp/ido.el Sun Dec 28 16:04:37 2003 +0000 +++ b/lisp/ido.el Sun Dec 28 16:05:28 2003 +0000 @@ -685,16 +685,17 @@ :type '(choice string (const nil)) :group 'ido) -(defcustom ido-decorations '( "{" "}" " | " " | ..." "[" "]" " [No match]" " [Matched]") +(defcustom ido-decorations '( "{" "}" " | " " | ..." "[" "]" " [No match]" " [Matched]" " [Not readable]") "*List of strings used by ido to display the alternatives in the minibuffer. -There are 8 elements in this list, each is a pair of strings: +There are 9 elements in this list: 1st and 2nd elements are used as brackets around the prospect list, 3rd element is the separator between prospects (ignored if ido-separator is set), 4th element is the string inserted at the end of a truncated list of prospects, 5th and 6th elements are used as brackets around the common match string which can be completed using TAB, 7th element is the string displayed when there are a no matches, and -8th element displayed if there is a single match (and faces are not used)." +8th element is displayed if there is a single match (and faces are not used). +9th element is displayed when the current directory is non-readable." :type '(repeat string) :group 'ido) @@ -931,6 +932,9 @@ ;; `ido-cur-list'. It is in no specific order. (defvar ido-ignored-list) +;; Remember if current directory is non-readable (so we cannot do completion). +(defvar ido-directory-nonreadable) + ;; Keep current item list if non-nil. (defvar ido-keep-item-list) @@ -1406,6 +1410,7 @@ (setq ido-current-directory dir) (if (get-buffer ido-completion-buffer) (kill-buffer ido-completion-buffer)) + (setq ido-directory-nonreadable (not (file-readable-p dir))) t)) (defun ido-set-current-home (&optional dir) @@ -1812,7 +1817,8 @@ buffer to be selected, which will go to the front of the list. If REQUIRE-MATCH is non-nil, an existing-buffer must be selected. If INITIAL is non-nil, it specifies the initial input string." - (let ((ido-current-directory nil)) + (let ((ido-current-directory nil) + (ido-directory-nonreadable nil)) (ido-read-internal 'buffer prompt 'ido-buffer-history default require-match initial))) (defun ido-record-work-directory (&optional dir) @@ -1851,12 +1857,18 @@ (if (> (length ido-work-file-list) ido-max-work-file-list) (setcdr (nthcdr (1- ido-max-work-file-list) ido-work-file-list) nil)))) +(defun ido-expand-directory (dir) + ;; Expand DIR or use DEFAULT-DIRECTORY if nil. + ;; Add final slash to result in case it was missing from DEFAULT-DIRECTORY. + (ido-final-slash (expand-file-name (or dir default-directory)) t)) + (defun ido-file-internal (method &optional fallback default prompt item initial) ;; Internal function for ido-find-file and friends (unless item (setq item 'file)) - (let ((ido-current-directory (expand-file-name (or default default-directory))) - filename) + (let* ((ido-current-directory (ido-expand-directory default)) + (ido-directory-nonreadable (not (file-readable-p ido-current-directory))) + filename) (cond ((or (not ido-mode) (ido-is-slow-ftp-host)) @@ -2693,30 +2705,33 @@ (setq ido-temp-list items))) (defun ido-file-name-all-completions1 (dir) - (if (and ido-enable-tramp-completion - (string-match "\\`/\\([^/:]+:\\([^/:@]+@\\)?\\)\\'" dir)) - - ;; Trick tramp's file-name-all-completions handler to DTRT, as it - ;; has some pretty obscure requirements. This seems to work... - ;; /ftp: => (f-n-a-c "/ftp:" "") - ;; /ftp:kfs: => (f-n-a-c "" "/ftp:kfs:") - ;; /ftp:kfs@ => (f-n-a-c "ftp:kfs@" "/") - ;; /ftp:kfs@kfs: => (f-n-a-c "" "/ftp:kfs@kfs:") - ;; Currently no attempt is made to handle multi: stuff. - - (let* ((prefix (match-string 1 dir)) - (user-flag (match-beginning 2)) - (len (and prefix (length prefix))) - compl) - (if user-flag - (setq dir (substring dir 1))) - (require 'tramp nil t) - (ido-trace "tramp complete" dir) - (setq compl (file-name-all-completions dir (if user-flag "/" ""))) - (if (> len 0) - (mapcar (lambda (c) (substring c len)) compl) - compl)) - (file-name-all-completions "" dir))) + (cond + ((not (file-readable-p dir)) '()) + ((and ido-enable-tramp-completion + (string-match "\\`/\\([^/:]+:\\([^/:@]+@\\)?\\)\\'" dir)) + + ;; Trick tramp's file-name-all-completions handler to DTRT, as it + ;; has some pretty obscure requirements. This seems to work... + ;; /ftp: => (f-n-a-c "/ftp:" "") + ;; /ftp:kfs: => (f-n-a-c "" "/ftp:kfs:") + ;; /ftp:kfs@ => (f-n-a-c "ftp:kfs@" "/") + ;; /ftp:kfs@kfs: => (f-n-a-c "" "/ftp:kfs@kfs:") + ;; Currently no attempt is made to handle multi: stuff. + + (let* ((prefix (match-string 1 dir)) + (user-flag (match-beginning 2)) + (len (and prefix (length prefix))) + compl) + (if user-flag + (setq dir (substring dir 1))) + (require 'tramp nil t) + (ido-trace "tramp complete" dir) + (setq compl (file-name-all-completions dir (if user-flag "/" ""))) + (if (> len 0) + (mapcar (lambda (c) (substring c len)) compl) + compl))) + (t + (file-name-all-completions "" dir)))) (defun ido-file-name-all-completions (dir) ;; Return name of all files in DIR @@ -3518,6 +3533,11 @@ (expand-file-name "/" ido-current-directory) "/")) (setq refresh t)) + ((and ido-directory-nonreadable + (file-directory-p (concat ido-current-directory (file-name-directory contents)))) + (ido-set-current-directory + (concat ido-current-directory (file-name-directory contents))) + (setq refresh t)) (t (ido-trace "try single dir") (setq try-single-dir-match t)))) @@ -3574,6 +3594,7 @@ (exit-minibuffer)) (when (and (not ido-matches) + (not ido-directory-nonreadable) ;; ido-rescan ? ido-process-ignore-lists ido-ignored-list) @@ -3596,7 +3617,8 @@ (memq ido-cur-item '(file dir)) (not (ido-is-root-directory)) (> (length contents) 1) - (not (string-match "[$]" contents))) + (not (string-match "[$]" contents)) + (not ido-directory-nonreadable)) (ido-trace "merge?") (if ido-use-merged-list (ido-undo-merge-work-directory contents nil) @@ -3658,9 +3680,12 @@ (setq comps (cons first (cdr comps))))) (cond ((null comps) - (if ido-report-no-match - (nth 6 ido-decorations) ;; [No Match] - "")) + (cond + (ido-directory-nonreadable + (or (nth 8 ido-decorations) " [Not readable]")) + (ido-report-no-match + (nth 6 ido-decorations)) ;; [No match] + (t ""))) ((null (cdr comps)) ;one match (concat (if (> (length (ido-name (car comps))) (length name)) @@ -3771,13 +3796,14 @@ (ido-read-directory-name prompt dir default-filename mustmatch initial)) ((and (not (memq this-command ido-read-file-name-non-ido)) (or (null predicate) (eq predicate 'file-exists-p))) - (let (filename - ido-saved-vc-hb - (vc-handled-backends (and (boundp 'vc-handled-backends) vc-handled-backends)) - (ido-current-directory (expand-file-name (or dir default-directory))) - (ido-work-directory-index -1) - (ido-work-file-index -1) - (ido-find-literal nil)) + (let* (filename + ido-saved-vc-hb + (vc-handled-backends (and (boundp 'vc-handled-backends) vc-handled-backends)) + (ido-current-directory (ido-expand-directory dir)) + (ido-directory-nonreadable (not (file-readable-p ido-current-directory))) + (ido-work-directory-index -1) + (ido-work-file-index -1) + (ido-find-literal nil)) (setq filename (ido-read-internal 'file prompt 'ido-file-history default-filename mustmatch initial)) (if filename @@ -3790,11 +3816,12 @@ (defun ido-read-directory-name (prompt &optional dir default-dirname mustmatch initial) "Read directory name, prompting with PROMPT and completing in directory DIR. See `read-file-name' for additional parameters." - (let (filename - ido-saved-vc-hb - (ido-current-directory (expand-file-name (or dir default-directory))) - (ido-work-directory-index -1) - (ido-work-file-index -1)) + (let* (filename + ido-saved-vc-hb + (ido-current-directory (ido-expand-directory dir)) + (ido-directory-nonreadable (not (file-readable-p ido-current-directory))) + (ido-work-directory-index -1) + (ido-work-file-index -1)) (setq filename (ido-read-internal 'dir prompt 'ido-file-history default-dirname mustmatch initial)) (if filename
--- a/lisp/jka-compr.el Sun Dec 28 16:04:37 2003 +0000 +++ b/lisp/jka-compr.el Sun Dec 28 16:05:28 2003 +0000 @@ -590,10 +590,11 @@ (file-exists-p local-copy) (delete-file local-copy))) - (decode-coding-inserted-region - (point) (+ (point) size) - (jka-compr-byte-compiler-base-file-name file) - visit beg end replace) + (unless notfound + (decode-coding-inserted-region + (point) (+ (point) size) + (jka-compr-byte-compiler-base-file-name file) + visit beg end replace)) (and visit
--- a/lisp/ls-lisp.el Sun Dec 28 16:04:37 2003 +0000 +++ b/lisp/ls-lisp.el Sun Dec 28 16:05:28 2003 +0000 @@ -267,7 +267,7 @@ (let* ((dir (file-name-as-directory file)) (default-directory dir) ; so that file-attributes works (file-alist - (directory-files-and-attributes dir nil wildcard-regexp t)) + (directory-files-and-attributes dir nil wildcard-regexp t 'string)) (now (current-time)) (sum 0) ;; do all bindings here for speed @@ -329,7 +329,7 @@ ;; so must make it a relative filename as ls does: (if (eq (aref file (1- (length file))) ?/) (setq file (substring file 0 -1))) - (let ((fattr (file-attributes file))) + (let ((fattr (file-attributes file 'string))) (if fattr (insert (ls-lisp-format file fattr (nth 7 fattr) switches time-index (current-time))) @@ -522,23 +522,14 @@ ;; They tend to be bogus on non-UNIX platforms anyway so ;; optionally hide them. (if (memq 'uid ls-lisp-verbosity) - ;; (user-login-name uid) works on Windows NT but not - ;; on 9x and maybe not on some other platforms, so... + ;; uid can be a sting or an integer (let ((uid (nth 2 file-attr))) - (if (= uid (user-uid)) - (format " %-8s" (user-login-name)) - (format " %-8d" uid)))) + (format (if (stringp uid) " %-8s" " %-8d") uid))) (if (not (memq ?G switches)) ; GNU ls -- shows group by default (if (or (memq ?g switches) ; UNIX ls -- no group by default (memq 'gid ls-lisp-verbosity)) - (if (memq system-type '(macos windows-nt ms-dos)) - ;; No useful concept of group... - " root" - (let* ((gid (nth 3 file-attr)) - (group (user-login-name gid))) - (if group - (format " %-8s" group) - (format " %-8d" gid)))))) + (let ((gid (nth 3 file-attr))) + (format (if (stringp gid) " %-8s" " %-8d") gid)))) (ls-lisp-format-file-size file-size (memq ?h switches)) " " (ls-lisp-format-time file-attr time-index now)
--- a/lisp/textmodes/texnfo-upd.el Sun Dec 28 16:04:37 2003 +0000 +++ b/lisp/textmodes/texnfo-upd.el Sun Dec 28 16:05:28 2003 +0000 @@ -1,6 +1,6 @@ ;;; texnfo-upd.el --- utilities for updating nodes and menus in Texinfo files -;; Copyright (C) 1989, 1990, 1991, 1992, 2001, 2002 Free Software Foundation, Inc. +;; Copyright (C) 1989, 1990, 1991, 1992, 2001, 2002, 2003 Free Software Foundation, Inc. ;; Author: Robert J. Chassell ;; Maintainer: bug-texinfo@gnu.org @@ -1795,25 +1795,34 @@ ;; description slot of a menu as a description. (let ((case-fold-search t) - menu-list next-node-name previous-node-name) + menu-list next-node-name previous-node-name files-with-node-lines) - ;; Find the name of the first node of the first included file. - (set-buffer (find-file-noselect (car (cdr files)))) + ;; Create a new list of included files that only have node lines + (while files + (set-buffer (find-file-noselect (car files))) + (widen) + (goto-char (point-min)) + (when (re-search-forward "^@node" nil t) + (setq files-with-node-lines (cons (car files) files-with-node-lines))) + (setq files (cdr files))) + (setq files-with-node-lines (nreverse files-with-node-lines)) + + ;; Find the name of the first node in a subsequent file + ;; and copy it into the variable next-node-name + (set-buffer (find-file-noselect (car (cdr files-with-node-lines)))) (widen) (goto-char (point-min)) - (if (not (re-search-forward "^@node" nil t)) - (error "No `@node' line found in %s" (buffer-name))) (beginning-of-line) (texinfo-check-for-node-name) (setq next-node-name (texinfo-copy-node-name)) - (push (cons next-node-name (prog1 "" (forward-line 1))) ;; Use following to insert section titles automatically. ;; (texinfo-copy-next-section-title) menu-list) ;; Go to outer file - (set-buffer (find-file-noselect (pop files))) + ;; `pop' is analogous to (prog1 (car PLACE) (setf PLACE (cdr PLACE))) + (set-buffer (find-file-noselect (pop files-with-node-lines))) (goto-char (point-min)) (if (not (re-search-forward "^@node [ \t]*top[ \t]*\\(,\\|$\\)" nil t)) (error "This buffer needs a Top node")) @@ -1824,18 +1833,16 @@ (beginning-of-line) (setq previous-node-name "Top") - (while files + (while files-with-node-lines - (if (not (cdr files)) + (if (not (cdr files-with-node-lines)) ;; No next file (setq next-node-name "") ;; Else, ;; find the name of the first node in the next file. - (set-buffer (find-file-noselect (car (cdr files)))) + (set-buffer (find-file-noselect (car (cdr files-with-node-lines)))) (widen) (goto-char (point-min)) - (if (not (re-search-forward "^@node" nil t)) - (error "No `@node' line found in %s" (buffer-name))) (beginning-of-line) (texinfo-check-for-node-name) (setq next-node-name (texinfo-copy-node-name)) @@ -1845,10 +1852,8 @@ menu-list)) ;; Go to node to be updated. - (set-buffer (find-file-noselect (car files))) + (set-buffer (find-file-noselect (car files-with-node-lines))) (goto-char (point-min)) - (if (not (re-search-forward "^@node" nil t)) - (error "No `@node' line found in %s" (buffer-name))) (beginning-of-line) ;; Update other menus and nodes if requested. @@ -1862,7 +1867,7 @@ (beginning-of-line) (setq previous-node-name (texinfo-copy-node-name)) - (setq files (cdr files))) + (setq files-with-node-lines (cdr files-with-node-lines))) (nreverse menu-list))) (defun texinfo-multi-files-insert-main-menu (menu-list)
--- a/lisp/wid-edit.el Sun Dec 28 16:04:37 2003 +0000 +++ b/lisp/wid-edit.el Sun Dec 28 16:05:28 2003 +0000 @@ -1267,6 +1267,42 @@ found (widget-apply child :validate))) found)) +(defun widget-child-value-get (widget) + "Get the value of the first member of :children in WIDGET." + (widget-value (car (widget-get widget :children)))) + +(defun widget-child-value-inline (widget) + "Get the inline value of the first member of :children in WIDGET." + (widget-apply (car (widget-get widget :children)) :value-inline)) + +(defun widget-child-validate (widget) + "The result of validating the first member of :children in WIDGET." + (widget-apply (car (widget-get widget :children)) :validate)) + +(defun widget-type-value-create (widget) + "Convert and instantiate the value of the :type attribute of WIDGET. +Store the newly created widget in the :children attribute. + +The value of the :type attribute should be an unconverted widget type." + (let ((value (widget-get widget :value)) + (type (widget-get widget :type))) + (widget-put widget :children + (list (widget-create-child-value widget + (widget-convert type) + value))))) + +(defun widget-type-default-get (widget) + "Get default value from the :type attribute of WIDGET. + +The value of the :type attribute should be an unconverted widget type." + (widget-default-get (widget-convert (widget-get widget :type)))) + +(defun widget-type-match (widget value) + "Non-nil if the :type value of WIDGET matches VALUE. + +The value of the :type attribute should be an unconverted widget type." + (widget-apply (widget-convert (widget-get widget :type)) :match value)) + (defun widget-types-copy (widget) "Copy :args as widget types in WIDGET." (widget-put widget :args (mapcar 'widget-copy (widget-get widget :args))) @@ -1862,9 +1898,8 @@ :tag "choice" :void '(item :format "invalid (%t)\n") :value-create 'widget-choice-value-create - :value-delete 'widget-children-value-delete - :value-get 'widget-choice-value-get - :value-inline 'widget-choice-value-inline + :value-get 'widget-child-value-get + :value-inline 'widget-child-value-inline :default-get 'widget-choice-default-get :mouse-down-action 'widget-choice-mouse-down-action :action 'widget-choice-action @@ -1901,14 +1936,6 @@ widget void :value value))) (widget-put widget :choice void)))))) -(defun widget-choice-value-get (widget) - ;; Get value of the child widget. - (widget-value (car (widget-get widget :children)))) - -(defun widget-choice-value-inline (widget) - ;; Get value of the child widget. - (widget-apply (car (widget-get widget :children)) :value-inline)) - (defun widget-choice-default-get (widget) ;; Get default for the first choice. (widget-default-get (car (widget-get widget :args)))) @@ -2099,7 +2126,6 @@ :entry-format "%b %v" :greedy nil :value-create 'widget-checklist-value-create - :value-delete 'widget-children-value-delete :value-get 'widget-checklist-value-get :validate 'widget-checklist-validate :match 'widget-checklist-match @@ -2276,7 +2302,6 @@ :format "%v" :entry-format "%b %v" :value-create 'widget-radio-value-create - :value-delete 'widget-children-value-delete :value-get 'widget-radio-value-get :value-inline 'widget-radio-value-inline :value-set 'widget-radio-value-set @@ -2466,7 +2491,6 @@ :format-handler 'widget-editable-list-format-handler :entry-format "%i %d %v" :value-create 'widget-editable-list-value-create - :value-delete 'widget-children-value-delete :value-get 'widget-editable-list-value-get :validate 'widget-children-validate :match 'widget-editable-list-match @@ -2637,7 +2661,6 @@ :copy 'widget-types-copy :format "%v" :value-create 'widget-group-value-create - :value-delete 'widget-children-value-delete :value-get 'widget-editable-list-value-get :default-get 'widget-group-default-get :validate 'widget-children-validate @@ -2803,7 +2826,6 @@ "A documentation string." :format "%v" :action 'widget-documentation-string-action - :value-delete 'widget-children-value-delete :value-create 'widget-documentation-string-value-create) (defun widget-documentation-string-value-create (widget) @@ -3250,6 +3272,62 @@ (widget-group-match widget (widget-apply widget :value-to-internal value)))) +;;; The `lazy' Widget. +;; +;; Recursive datatypes. + +(define-widget 'lazy 'default + "Base widget for recursive datastructures. + +The `lazy' widget will, when instantiated, contain a single inferior +widget, of the widget type specified by the :type parameter. The +value of the `lazy' widget is the same as the value of the inferior +widget. When deriving a new widget from the 'lazy' widget, the :type +parameter is allowed to refer to the widget currently being defined, +thus allowing recursive datastructures to be described. + +The :type parameter takes the same arguments as the defcustom +parameter with the same name. + +Most composite widgets, i.e. widgets containing other widgets, does +not allow recursion. That is, when you define a new widget type, none +of the inferior widgets may be of the same type you are currently +defining. + +In Lisp, however, it is custom to define datastructures in terms of +themselves. A list, for example, is defined as either nil, or a cons +cell whose cdr itself is a list. The obvious way to translate this +into a widget type would be + + (define-widget 'my-list 'choice + \"A list of sexps.\" + :tag \"Sexp list\" + :args '((const nil) (cons :value (nil) sexp my-list))) + +Here we attempt to define my-list as a choice of either the constant +nil, or a cons-cell containing a sexp and my-lisp. This will not work +because the `choice' widget does not allow recursion. + +Using the `lazy' widget you can overcome this problem, as in this +example: + + (define-widget 'sexp-list 'lazy + \"A list of sexps.\" + :tag \"Sexp list\" + :type '(choice (const nil) (cons :value (nil) sexp sexp-list)))" + :format "%{%t%}: %v" + ;; We don't convert :type because we want to allow recursive + ;; datastructures. This is slow, so we should not create speed + ;; critical widgets by deriving from this. + :convert-widget 'widget-value-convert-widget + :value-create 'widget-type-value-create + :value-get 'widget-child-value-get + :value-inline 'widget-child-value-inline + :default-get 'widget-type-default-get + :match 'widget-type-match + :validate 'widget-child-validate) + + ;;; The `plist' Widget. ;; ;; Property lists.
--- a/lispref/ChangeLog Sun Dec 28 16:04:37 2003 +0000 +++ b/lispref/ChangeLog Sun Dec 28 16:05:28 2003 +0000 @@ -1,3 +1,51 @@ +2003-12-25 Markus Rost <rost@mathematik.uni-bielefeld.de> + + * display.texi (Fringes): Fix typo "set-buffer-window". + +2003-12-24 Luc Teirlinck <teirllm@auburn.edu> + + * display.texi, eval.texi, help.texi, internals.texi, loading.texi: + * nonascii.texi, processes.texi, tips.texi, variables.texi: + Add or change various xrefs and anchors. + + * commands.texi: Replace all occurrences of @acronym{CAR} with + @sc{car}, for consistency with the rest of the Elisp manual. + `car' and `cdr' are historically acronyms, but are no longer + widely thought of as such. + + * internals.texi (Pure Storage): Mention that `purecopy' does not + copy text properties. + (Object Internals): Now 29 bits are used (in most implementations) + to address Lisp objects. + + * variables.texi (Variables with Restricted Values): New node. + + * objects.texi (Lisp Data Types): Mention that certain variables + can only take on a restricted set of values and add an xref to + the new node "Variables with Restricted Values". + + * eval.texi (Function Indirection): Describe the errors that + `indirect-function' can signal. + (Eval): Clarify the descriptions of `eval-region' and `values'. + Describe `eval-buffer' instead of `eval-current-buffer' and + mention `eval-current-buffer' as an alias for `current-buffer'. + Correct the description and mention all optional arguments. + + * nonascii.texi : Various small changes in addition to the + following. + (Converting Representations): Clarify behavior of + `string-make-multibyte' and `string-to-multibyte' for unibyte all + ASCII arguments. + (Character Sets): Document the variable `charset-list' and adapt + the definition of the function `charset-list' accordingly. + (Translation of Characters): Clarify use of generic characters in + `make-translation-table'. Clarify and correct the description of + the use of translation tables in encoding and decoding. + (User-Chosen Coding Systems): Correct and clarify the description + of `select-safe-coding-system'. + (Default Coding Systems): Clarify description of + `file-coding-system-alist'. + 2003-11-30 Luc Teirlinck <teirllm@auburn.edu> * strings.texi (Text Comparison): Correctly describe when two @@ -42,7 +90,7 @@ 2003-11-20 Luc Teirlinck <teirllm@auburn.edu> - * positions.texi (Positions): Mention that, if a marker is used a + * positions.texi (Positions): Mention that, if a marker is used as a position, its buffer is ignored. * markers.texi (Overview of Markers): Mention it here too.
--- a/lispref/commands.texi Sun Dec 28 16:04:37 2003 +0000 +++ b/lispref/commands.texi Sun Dec 28 16:05:28 2003 +0000 @@ -1096,7 +1096,7 @@ Emacs supports four kinds of mouse events: click events, drag events, button-down events, and motion events. All mouse events are represented -as lists. The @acronym{CAR} of the list is the event type; this says which +as lists. The @sc{car} of the list is the event type; this says which mouse button was involved, and which modifier keys were used with it. The event type can also distinguish double or triple button presses (@pxref{Repeat Events}). The rest of the list elements give position @@ -1172,7 +1172,7 @@ @item @var{x}, @var{y} These are the pixel-denominated coordinates of the click, relative to -the top left corner of @var{window}, which is @code{(0 . 0)}. +the top left corner of @var{window}, which is @code{(0 . 0)}. For the mode or header line, @var{y} does not have meaningful data. For the vertical line, @var{x} does not have meaningful data. @@ -1188,7 +1188,7 @@ @item @var{string} This is the string on which the click occurred, including any -properties. +properties. @item @var{string-pos} This is the position in the string on which the click occurred, @@ -1560,7 +1560,7 @@ key binding purposes. For a keyboard event, the event type equals the event value; thus, the event type for a character is the character, and the event type for a function key symbol is the symbol itself. For -events that are lists, the event type is the symbol in the @acronym{CAR} of +events that are lists, the event type is the symbol in the @sc{car} of the list. Thus, the event type is always a symbol or a character. Two events of the same type are equivalent where key bindings are @@ -2583,7 +2583,7 @@ value, @var{arg}. The argument may be a symbol, a number, or a list. If it is @code{nil}, the value 1 is returned; if it is @code{-}, the value @minus{}1 is returned; if it is a number, that number is returned; -if it is a list, the @acronym{CAR} of that list (which should be a number) is +if it is a list, the @sc{car} of that list (which should be a number) is returned. @end defun
--- a/lispref/customize.texi Sun Dec 28 16:04:37 2003 +0000 +++ b/lispref/customize.texi Sun Dec 28 16:05:28 2003 +0000 @@ -1,6 +1,6 @@ @c -*-texinfo-*- @c This is part of the GNU Emacs Lisp Reference Manual. -@c Copyright (C) 1997, 1998, 1999, 2000, 2002 Free Software Foundation, Inc. +@c Copyright (C) 1997, 1998, 1999, 2000, 2002, 2003 Free Software Foundation, Inc. @c See the file elisp.texi for copying conditions. @setfilename ../info/customize @node Customization, Loading, Macros, Top @@ -373,6 +373,7 @@ * Composite Types:: * Splicing into Lists:: * Type Keywords:: +* Defining New Types:: @end menu All customization types are implemented as widgets; see @ref{Top, , @@ -1056,6 +1057,76 @@ @end ignore @end table +@node Defining New Types +@subsection Defining New Types + +In the previous sections we have described how to construct elaborate +type specifications for @code{defcustom}. In some cases you may want to +give such a type specification a name. The obvious case is when you are +using the same type for many user options, rather than repeat the +specification for each option, you can give the type specification a +name once, and use that name each @code{defcustom}. The other case is +when a user option accept a recursive datastructure. To make it +possible for a datatype to refer to itself, it needs to have a name. + +Since custom types are implemented as widgets, the way to define a new +customize type is to define a new widget. We are not going to describe +the widget interface here in details, see @ref{Top, , Introduction, +widget, The Emacs Widget Library}, for that. Instead we are going to +demonstrate the minimal functionality needed for defining new customize +types by a simple example. + +@example +(define-widget 'binary-tree-of-string 'lazy + "A binary tree made of cons-cells and strings." + :offset 4 + :tag "Node" + :type '(choice (string :tag "Leaf" :value "") + (cons :tag "Interior" + :value ("" . "") + binary-tree-of-string + binary-tree-of-string))) + +(defcustom foo-bar "" + "Sample variable holding a binary tree of strings." + :type 'binary-tree-of-string) +@end example + +The function to define a new widget is name @code{define-widget}. The +first argument is the symbol we want to make a new widget type. The +second argument is a symbol representing an existing widget, the new +widget is going to be defined in terms of difference from the existing +widget. For the purpose of defining new customization types, the +@code{lazy} widget is perfect, because it accept a @code{:type} keyword +argument with the same syntax as the keyword argument to +@code{defcustom} with the same name. The third argument is a +documentation string for the new widget. You will be able to see that +string with the @kbd{M-x widget-browse @key{ret} binary-tree-of-string +@key{ret}} command. + +After these mandatory arguments follows the keyword arguments. The most +important is @code{:type}, which describes the datatype we want to match +with this widget. Here a @code{binary-tree-of-string} is described as +being either a string, or a cons-cell whose car and cdr are themselves +both @code{binary-tree-of-string}. Note the reference to the widget +type we are currently in the process of defining. The @code{:tag} +attribute is a string to name the widget in the user interface, and the +@code{:offset} argument are there to ensure that child nodes are +indented four spaces relatively to the parent node, making the tree +structure apparent in the customization buffer. + +The @code{defcustom} shows how the new widget can be used as an ordinary +customization type. + +If you wonder about the name @code{lazy}, know that the other composite +widgets convert their inferior widgets to internal form when the widget +is instantiated in a buffer. This conversion is recursive, so the +inferior widgets will convert @emph{their} inferior widgets. If the +datastructure is itself recursive, this conversion will go on forever, +or at least until Emacs run out of stack space. The @code{lazy} widget +stop this recursion, it will only convert its @code{:type} argument when +needed. + @ignore arch-tag: d1b8fad3-f48c-4ce4-a402-f73b5ef19bd2 @end ignore
--- a/lispref/display.texi Sun Dec 28 16:04:37 2003 +0000 +++ b/lispref/display.texi Sun Dec 28 16:05:28 2003 +0000 @@ -805,8 +805,9 @@ so that it is still Help mode at the end of their execution, then @code{with-output-to-temp-buffer} makes this buffer read-only at the end, and also scans it for function and variable names to make them -into clickable cross-references. @xref{Documentation Tips, , Tips for -Documentation Strings}. +into clickable cross-references. @xref{Docstring hyperlinks, , Tips +for Documentation Strings}, in particular the item on hyperlinks in +documentation strings, for more details. The string @var{buffer-name} specifies the temporary buffer, which need not already exist. The argument must be a string, not a buffer. @@ -2527,7 +2528,7 @@ The values of these variables take effect when you display the buffer in a window. If you change them while the buffer is visible, -you can call @code{set-buffer-window} to display it in a window again. +you can call @code{set-window-buffer} to display it in a window again. @defun set-window-fringes window left &optional right outside-margins This function sets the fringe widthes of window @var{window}.
--- a/lispref/eval.texi Sun Dec 28 16:04:37 2003 +0000 +++ b/lispref/eval.texi Sun Dec 28 16:05:28 2003 +0000 @@ -319,6 +319,10 @@ definition and starts over with that value. If @var{function} is not a symbol, then it returns @var{function} itself. +This function signals a @code{void-function} error if the final +symbol is unbound and a @code{cyclic-function-indirection} error if +there is a loop in the chain of symbols. + Here is how you could define @code{indirect-function} in Lisp: @smallexample @@ -625,32 +629,51 @@ @code{max-lisp-eval-depth} (see below). @end defun +@anchor{Definition of eval-region} @deffn Command eval-region start end &optional stream read-function This function evaluates the forms in the current buffer in the region defined by the positions @var{start} and @var{end}. It reads forms from the region and calls @code{eval} on them until the end of the region is reached, or until an error is signaled and not handled. -If @var{stream} is non-@code{nil}, the values that result from -evaluating the expressions in the region are printed using @var{stream}. -@xref{Output Streams}. +By default, @code{eval-region} does not produce any output. However, +if @var{stream} is non-@code{nil}, any output produced by output +functions (@pxref{Output Functions}), as well as the values that +result from evaluating the expressions in the region are printed using +@var{stream}. @xref{Output Streams}. -If @var{read-function} is non-@code{nil}, it should be a function, which -is used instead of @code{read} to read expressions one by one. This -function is called with one argument, the stream for reading input. You -can also use the variable @code{load-read-function} (@pxref{How Programs -Do Loading}) to specify this function, but it is more robust to use the +If @var{read-function} is non-@code{nil}, it should be a function, +which is used instead of @code{read} to read expressions one by one. +This function is called with one argument, the stream for reading +input. You can also use the variable @code{load-read-function} +(@pxref{Definition of load-read-function,, How Programs Do Loading}) +to specify this function, but it is more robust to use the @var{read-function} argument. -@code{eval-region} always returns @code{nil}. +@code{eval-region} does not move point. It always returns @code{nil}. @end deffn @cindex evaluation of buffer contents -@deffn Command eval-current-buffer &optional stream -This is like @code{eval-region} except that it operates on the whole -buffer. +@deffn Command eval-buffer &optional buffer-or-name stream filename unibyte print +This is similar to @code{eval-region}, but the arguments provide +different optional features. @code{eval-buffer} operates on the +entire accessible portion of buffer @var{buffer-or-name}. +@var{buffer-or-name} can be a buffer, a buffer name (a string), or +@code{nil} (or omitted), which means to use the current buffer. +@var{stream} is used as in @code{eval-region}, unless @var{stream} is +@code{nil} and @var{print} non-@code{nil}. In that case, values that +result from evaluating the expressions are still discarded, but the +output of the output functions is printed in the echo area. +@var{filename} is the file name to use for @code{load-history} +(@pxref{Unloading}), and defaults to @code{buffer-file-name} +(@pxref{Buffer File Name}). If @var{unibyte} is non-@code{nil}, +@code{read} converts strings to unibyte whenever possible. + +@findex eval-current-buffer +@code{eval-current-buffer} is an alias for this command. @end deffn +@anchor{Definition of max-lisp-eval-depth} @defvar max-lisp-eval-depth This variable defines the maximum depth allowed in calls to @code{eval}, @code{apply}, and @code{funcall} before an error is signaled (with error @@ -670,14 +693,17 @@ left, to make sure the debugger itself has room to execute. @code{max-specpdl-size} provides another limit on nesting. -@xref{Local Variables}. +@xref{Definition of max-specpdl-size,, Local Variables}. @end defvar @defvar values The value of this variable is a list of the values returned by all the expressions that were read, evaluated, and printed from buffers -(including the minibuffer) by the standard Emacs commands which do this. -The elements are ordered most recent first. +(including the minibuffer) by the standard Emacs commands which do +this. (Note that this does @emph{not} include evaluation in +@samp{*ielm*} buffers, nor evaluation using @kbd{C-j} in +@code{lisp-interaction-mode}.) The elements are ordered most recent +first. @example @group
--- a/lispref/help.texi Sun Dec 28 16:04:37 2003 +0000 +++ b/lispref/help.texi Sun Dec 28 16:05:28 2003 +0000 @@ -259,6 +259,7 @@ user option; see the description of @code{defvar} in @ref{Defining Variables}. +@anchor{Definition of Snarf-documentation} @defun Snarf-documentation filename This function is used only during Emacs initialization, just before the runnable Emacs is dumped. It finds the file offsets of the
--- a/lispref/internals.texi Sun Dec 28 16:04:37 2003 +0000 +++ b/lispref/internals.texi Sun Dec 28 16:05:28 2003 +0000 @@ -81,8 +81,9 @@ After @file{loadup.el} reads @file{site-load.el}, it finds the documentation strings for primitive and preloaded functions (and -variables) in the file @file{etc/DOC} where they are stored, by calling -@code{Snarf-documentation} (@pxref{Accessing Documentation}). +variables) in the file @file{etc/DOC} where they are stored, by +calling @code{Snarf-documentation} (@pxref{Definition of +Snarf-documentation,, Accessing Documentation}). @cindex @file{site-init.el} You can specify other Lisp expressions to execute just before dumping @@ -151,10 +152,10 @@ @defun purecopy object This function makes a copy in pure storage of @var{object}, and returns it. It copies a string by simply making a new string with the same -characters in pure storage. It recursively copies the contents of -vectors and cons cells. It does not make copies of other objects such -as symbols, but just returns them unchanged. It signals an error if -asked to copy markers. +characters, but without text properties, in pure storage. It +recursively copies the contents of vectors and cons cells. It does +not make copies of other objects such as symbols, but just returns +them unchanged. It signals an error if asked to copy markers. This function is a no-op except while Emacs is being built and dumped; it is usually called only in the file @file{emacs/lisp/loaddefs.el}, but @@ -367,7 +368,7 @@ @code{garbage-collect} will set the threshold back to 10,000. @end defopt - The value return by @code{garbage-collect} describes the amount of + The value returned by @code{garbage-collect} describes the amount of memory used by Lisp data, broken down by data type. By contrast, the function @code{memory-limit} provides information on the total amount of memory Emacs is currently using. @@ -595,9 +596,9 @@ GC-protected; as long as the object is not recycled, all pointers to it remain valid. So if you are sure that a local variable points to an object that will be preserved by some other pointer, that local -variable does not need a GCPRO. (Formerly, strings were an exception -to this rule; in older Emacs versions, every pointer to a string -needed to be marked by GC.) +variable does not need a @code{GCPRO}. (Formerly, strings were an +exception to this rule; in older Emacs versions, every pointer to a +string needed to be marked by GC.) The macro @code{GCPRO1} protects just one local variable. If you want to protect two, use @code{GCPRO2} instead; repeating @@ -612,7 +613,7 @@ accept two arguments at the C level: the number of Lisp arguments, and a @code{Lisp_Object *} pointer to a C vector containing those Lisp arguments. This C vector may be part of a Lisp vector, but it need -not be. The responsibility for using GCPRO to protecting the Lisp +not be. The responsibility for using @code{GCPRO} to protect the Lisp arguments from GC if necessary rests with the caller in this case, since the caller allocated or found the storage for them. @@ -651,6 +652,7 @@ of these functions are called, and add a call to @code{syms_of_@var{filename}} there. +@anchor{Defining Lisp variables in C} @vindex byte-boolean-vars The function @code{syms_of_@var{filename}} is also the place to define any C variables that are to be visible as Lisp variables. @@ -761,9 +763,9 @@ data are stored in a heap and the only access that programs have to it is through pointers. Pointers are thirty-two bits wide in most implementations. Depending on the operating system and type of machine -for which you compile Emacs, twenty-eight bits are used to address the -object, and the remaining four bits are used for a GC mark bit and the -tag that identifies the object's type. +for which you compile Emacs, twenty-nine bits are used to address the +object, and the remaining three bits are used for the tag that +identifies the object's type. Because Lisp objects are represented as tagged pointers, it is always possible to determine the Lisp data type of any object. The C data type
--- a/lispref/loading.texi Sun Dec 28 16:04:37 2003 +0000 +++ b/lispref/loading.texi Sun Dec 28 16:05:28 2003 +0000 @@ -140,6 +140,7 @@ file, and it is @code{nil} otherwise. @end defvar +@anchor{Definition of load-read-function} @defvar load-read-function This variable specifies an alternate expression-reading function for @code{load} and @code{eval-region} to use instead of @code{read}. @@ -150,7 +151,7 @@ Instead of using this variable, it is cleaner to use another, newer feature: to pass the function as the @var{read-function} argument to -@code{eval-region}. @xref{Eval}. +@code{eval-region}. @xref{Definition of eval-region,, Eval}. @end defvar For information about how @code{load} is used in building Emacs, see
--- a/lispref/nonascii.texi Sun Dec 28 16:04:37 2003 +0000 +++ b/lispref/nonascii.texi Sun Dec 28 16:05:28 2003 +0000 @@ -96,13 +96,15 @@ @defun position-bytes position @tindex position-bytes Return the byte-position corresponding to buffer position @var{position} -in the current buffer. +in the current buffer. If @var{position} is out of range, the value +is @code{nil}. @end defun @defun byte-to-position byte-position @tindex byte-to-position Return the buffer position corresponding to byte-position -@var{byte-position} in the current buffer. +@var{byte-position} in the current buffer. If @var{byte-position} is +out of range, the value is @code{nil}. @end defun @defun multibyte-string-p string @@ -173,6 +175,9 @@ If this is non-@code{nil}, it overrides @code{nonascii-insert-offset}. @end defvar +The next three functions either return the argument @var{string}, or a +newly created string with no text properties. + @defun string-make-unibyte string This function converts the text of @var{string} to unibyte representation, if it isn't already, and returns the result. If @@ -186,15 +191,23 @@ @defun string-make-multibyte string This function converts the text of @var{string} to multibyte representation, if it isn't already, and returns the result. If -@var{string} is a multibyte string, it is returned unchanged. -The function @code{unibyte-char-to-multibyte} is used to convert -each unibyte character to a multibyte character. +@var{string} is a multibyte string or consists entirely of +@acronym{ASCII} characters, it is returned unchanged. In particular, +if @var{string} is unibyte and entirely @acronym{ASCII}, the returned +string is unibyte. (When the characters are all @acronym{ASCII}, +Emacs primitives will treat the string the same way whether it is +unibyte or multibyte.) If @var{string} is unibyte and contains +non-@acronym{ASCII} characters, the function +@code{unibyte-char-to-multibyte} is used to convert each unibyte +character to a multibyte character. @end defun @defun string-to-multibyte string This function returns a multibyte string containing the same sequence -of character codes as @var{string}. If @var{string} is a multibyte -string, the value is the equal to @var{string}. +of character codes as @var{string}. Unlike +@code{string-make-multibyte}, this function unconditionally returns a +multibyte string. If @var{string} is a multibyte string, it is +returned unchanged. @end defun @node Selecting a Representation @@ -280,8 +293,8 @@ @end example If the optional argument @var{genericp} is non-@code{nil}, this -function returns @code{t} if @var{charcode} is a generic character -(@pxref{Splitting Characters}). +function also returns @code{t} if @var{charcode} is a generic +character (@pxref{Splitting Characters}). @end defun @node Character Sets @@ -311,13 +324,19 @@ @code{nil} otherwise. @end defun +@defvar charset-list +The value is a list of all defined character set names. +@end defvar + @defun charset-list -This function returns a list of all defined character set names. +This function returns the value of @code{charset-list}. It is only +provided for backward compatibility. @end defun @defun char-charset character This function returns the name of the character set that @var{character} -belongs to. +belongs to, or the symbol @code{unknown} if @var{character} is not a +valid character. @end defun @defun charset-plist charset @@ -378,6 +397,9 @@ identify @var{character} within that character set. The number of byte values is the character set's dimension. +If @var{character} is invalid as a character code, @code{split-char} +returns a list consisting of the symbol @code{unknown} and @var{character}. + @example (split-char 2248) @result{} (latin-iso8859-1 72) @@ -463,11 +485,11 @@ @cindex character translation tables @cindex translation tables - A @dfn{translation table} specifies a mapping of characters -into characters. These tables are used in encoding and decoding, and -for other purposes. Some coding systems specify their own particular -translation tables; there are also default translation tables which -apply to all other coding systems. + A @dfn{translation table} is a char-table that specifies a mapping +of characters into characters. These tables are used in encoding and +decoding, and for other purposes. Some coding systems specify their +own particular translation tables; there are also default translation +tables which apply to all other coding systems. @defun make-translation-table &rest translations This function returns a translation table based on the argument @@ -483,24 +505,30 @@ You can also map one whole character set into another character set with the same dimension. To do this, you specify a generic character (which designates a character set) for @var{from} (@pxref{Splitting Characters}). -In this case, @var{to} should also be a generic character, for another -character set of the same dimension. Then the translation table -translates each character of @var{from}'s character set into the -corresponding character of @var{to}'s character set. +In this case, if @var{to} is also a generic character, its character +set should have the same dimension as @var{from}'s. Then the +translation table translates each character of @var{from}'s character +set into the corresponding character of @var{to}'s character set. If +@var{from} is a generic character and @var{to} is an ordinary +character, then the translation table translates every character of +@var{from}'s character set into @var{to}. @end defun In decoding, the translation table's translations are applied to the characters that result from ordinary decoding. If a coding system has -property @code{character-translation-table-for-decode}, that specifies -the translation table to use. Otherwise, if -@code{standard-translation-table-for-decode} is non-@code{nil}, decoding -uses that table. +property @code{translation-table-for-decode}, that specifies the +translation table to use. (This is a property of the coding system, +as returned by @code{coding-system-get}, not a property of the symbol +that is the coding system's name. @xref{Coding System Basics,, Basic +Concepts of Coding Systems}.) Otherwise, if +@code{standard-translation-table-for-decode} is non-@code{nil}, +decoding uses that table. In encoding, the translation table's translations are applied to the characters in the buffer, and the result of translation is actually encoded. If a coding system has property -@code{character-translation-table-for-encode}, that specifies the -translation table to use. Otherwise the variable +@code{translation-table-for-encode}, that specifies the translation +table to use. Otherwise the variable @code{standard-translation-table-for-encode} specifies the translation table. @@ -516,7 +544,8 @@ @defvar translation-table-for-input Self-inserting characters are translated through this translation -table before they are inserted. +table before they are inserted. This variable automatically becomes +buffer-local when set. @end defvar @node Coding Systems @@ -686,7 +715,7 @@ @defun coding-system-p object This function returns @code{t} if @var{object} is a coding system -name. +name or @code{nil}. @end defun @defun check-coding-system coding-system @@ -701,6 +730,9 @@ @var{eol-type} should be @code{unix}, @code{dos}, @code{mac}, or @code{nil}. If it is @code{nil}, the returned coding system determines the end-of-line conversion from the data. + +@var{eol-type} may also be 0, 1 or 2, standing for @code{unix}, +@code{dos} and @code{mac}, respectively. @end defun @defun coding-system-change-text-conversion eol-coding text-coding @@ -745,55 +777,79 @@ priority. If the region contains only @acronym{ASCII} characters, the value -is @code{undecided} or @code{(undecided)}. +is @code{undecided} or @code{(undecided)}, or a variant specifying +end-of-line conversion, if that can be deduced from the text. @end defun -@defun detect-coding-string string highest +@defun detect-coding-string string &optional highest This function is like @code{detect-coding-region} except that it operates on the contents of @var{string} instead of bytes in the buffer. @end defun - @xref{Process Information}, for how to examine or set the coding -systems used for I/O to a subprocess. + @xref{Coding systems for a subprocess,, Process Information}, in +particular the description of the functions +@code{process-coding-system} and @code{set-process-coding-system}, for +how to examine or set the coding systems used for I/O to a subprocess. @node User-Chosen Coding Systems @subsection User-Chosen Coding Systems @cindex select safe coding system -@defun select-safe-coding-system from to &optional default-coding-system accept-default-p +@defun select-safe-coding-system from to &optional default-coding-system accept-default-p file This function selects a coding system for encoding specified text, asking the user to choose if necessary. Normally the specified text -is the text in the current buffer between @var{from} and @var{to}, -defaulting to the whole buffer if they are @code{nil}. If @var{from} -is a string, the string specifies the text to encode, and @var{to} is -ignored. +is the text in the current buffer between @var{from} and @var{to}. If +@var{from} is a string, the string specifies the text to encode, and +@var{to} is ignored. If @var{default-coding-system} is non-@code{nil}, that is the first coding system to try; if that can handle the text, @code{select-safe-coding-system} returns that coding system. It can also be a list of coding systems; then the function tries each of them -one by one. After trying all of them, it next tries the user's most -preferred coding system (@pxref{Recognize Coding, -prefer-coding-system, the description of @code{prefer-coding-system}, -emacs, GNU Emacs Manual}), and after that the current buffer's value -of @code{buffer-file-coding-system} (if it is not @code{undecided}). +one by one. After trying all of them, it next tries the current +buffer's value of @code{buffer-file-coding-system} (if it is not +@code{undecided}), then the value of +@code{default-buffer-file-coding-system} and finally the user's most +preferred coding system, which the user can set using the command +@code{prefer-coding-system} (@pxref{Recognize Coding,, Recognizing +Coding Systems, emacs, The GNU Emacs Manual}). If one of those coding systems can safely encode all the specified text, @code{select-safe-coding-system} chooses it and returns it. Otherwise, it asks the user to choose from a list of coding systems which can encode all the text, and returns the user's choice. +@var{default-coding-system} can also be a list whose first element is +t and whose other elements are coding systems. Then, if no coding +system in the list can handle the text, @code{select-safe-coding-system} +queries the user immediately, without trying any of the three +alternatives described above. + The optional argument @var{accept-default-p}, if non-@code{nil}, -should be a function to determine whether the coding system selected -without user interaction is acceptable. If this function returns -@code{nil}, the silently selected coding system is rejected, and the -user is asked to select a coding system from a list of possible -candidates. +should be a function to determine whether a coding system selected +without user interaction is acceptable. @code{select-safe-coding-system} +calls this function with one argument, the base coding system of the +selected coding system. If @var{accept-default-p} returns @code{nil}, +@code{select-safe-coding-system} rejects the silently selected coding +system, and asks the user to select a coding system from a list of +possible candidates. @vindex select-safe-coding-system-accept-default-p If the variable @code{select-safe-coding-system-accept-default-p} is non-@code{nil}, its value overrides the value of @var{accept-default-p}. + +As a final step, before returning the chosen coding system, +@code{select-safe-coding-system} checks whether that coding system is +consistent with what would be selected if the contents of the region +were read from a file. (If not, this could lead to data corruption in +a file subsequently re-visited and edited.) Normally, +@code{select-safe-coding-system} uses @code{buffer-file-name} as the +file for this purpose, but if @var{file} is non-@code{nil}, it uses +that file instead (this can be relevant for @code{write-region} and +similar functions). If it detects an apparent inconsistency, +@code{select-safe-coding-system} queries the user before selecting the +coding system. @end defun Here are two functions you can use to let the user specify a coding @@ -846,17 +902,19 @@ expression that matches certain file names. The element applies to file names that match @var{pattern}. -The @acronym{CDR} of the element, @var{coding}, should be either a coding +The @sc{cdr} of the element, @var{coding}, should be either a coding system, a cons cell containing two coding systems, or a function name (a symbol with a function definition). If @var{coding} is a coding system, that coding system is used for both reading the file and writing it. If -@var{coding} is a cons cell containing two coding systems, its @acronym{CAR} -specifies the coding system for decoding, and its @acronym{cdr} specifies the +@var{coding} is a cons cell containing two coding systems, its @sc{car} +specifies the coding system for decoding, and its @sc{cdr} specifies the coding system for encoding. -If @var{coding} is a function name, the function must return a coding -system or a cons cell containing two coding systems. This value is used -as described above. +If @var{coding} is a function name, the function should take one +argument, a list of all arguments passed to +@code{find-operation-coding-system}. It must return a coding system +or a cons cell containing two coding systems. This value has the same +meaning as described above. @end defvar @defvar process-coding-system-alist @@ -923,7 +981,7 @@ form: @example -(@var{decoding-system} @var{encoding-system}) +(@var{decoding-system} . @var{encoding-system}) @end example The first element, @var{decoding-system}, is the coding system to use @@ -948,7 +1006,6 @@ This function looks up the target in @code{file-coding-system-alist}, @code{process-coding-system-alist}, or @code{network-coding-system-alist}, depending on @var{operation}. -@xref{Default Coding Systems}. @end defun @node Specifying Coding Systems @@ -1040,33 +1097,41 @@ are meant to operate on sequences of bytes. All of these functions discard text properties. -@defun encode-coding-region start end coding-system -This function encodes the text from @var{start} to @var{end} according +@deffn Command encode-coding-region start end coding-system +This command encodes the text from @var{start} to @var{end} according to coding system @var{coding-system}. The encoded text replaces the original text in the buffer. The result of encoding is logically a sequence of bytes, but the buffer remains multibyte if it was multibyte before. -@end defun -@defun encode-coding-string string coding-system +This command returns the length of the encoded text. +@end deffn + +@defun encode-coding-string string coding-system &optional nocopy This function encodes the text in @var{string} according to coding system @var{coding-system}. It returns a new string containing the -encoded text. The result of encoding is a unibyte string. +encoded text, except when @var{nocopy} is non-@code{nil}, in which +case the function may return @var{string} itself if the encoding +operation is trivial. The result of encoding is a unibyte string. @end defun -@defun decode-coding-region start end coding-system -This function decodes the text from @var{start} to @var{end} according +@deffn Command decode-coding-region start end coding-system +This command decodes the text from @var{start} to @var{end} according to coding system @var{coding-system}. The decoded text replaces the original text in the buffer. To make explicit decoding useful, the text before decoding ought to be a sequence of byte values, but both multibyte and unibyte buffers are acceptable. -@end defun -@defun decode-coding-string string coding-system +This command returns the length of the decoded text. +@end deffn + +@defun decode-coding-string string coding-system &optional nocopy This function decodes the text in @var{string} according to coding system @var{coding-system}. It returns a new string containing the -decoded text. To make explicit decoding useful, the contents of -@var{string} ought to be a sequence of byte values, but a multibyte +decoded text, except when @var{nocopy} is non-@code{nil}, in which +case the function may return @var{string} itself if the decoding +operation is trivial. To make explicit decoding useful, the contents +of @var{string} ought to be a sequence of byte values, but a multibyte string is acceptable. @end defun @@ -1095,22 +1160,22 @@ keyboard input---or @code{nil} if no coding system is to be used. @end defun -@defun set-keyboard-coding-system coding-system -This function specifies @var{coding-system} as the coding system to +@deffn Command set-keyboard-coding-system coding-system +This command specifies @var{coding-system} as the coding system to use for decoding keyboard input. If @var{coding-system} is @code{nil}, that means do not decode keyboard input. -@end defun +@end deffn @defun terminal-coding-system This function returns the coding system that is in use for encoding terminal output---or @code{nil} for no encoding. @end defun -@defun set-terminal-coding-system coding-system -This function specifies @var{coding-system} as the coding system to use +@deffn Command set-terminal-coding-system coding-system +This command specifies @var{coding-system} as the coding system to use for encoding terminal output. If @var{coding-system} is @code{nil}, that means do not encode terminal output. -@end defun +@end deffn @node MS-DOS File Types @subsection MS-DOS File Types @@ -1193,18 +1258,18 @@ buffer now. @end defvar -@defvar default-input-method +@defopt default-input-method This variable holds the default input method for commands that choose an input method. Unlike @code{current-input-method}, this variable is normally global. -@end defvar +@end defopt -@defun set-input-method input-method -This function activates input method @var{input-method} for the current +@deffn Command set-input-method input-method +This command activates input method @var{input-method} for the current buffer. It also sets @code{default-input-method} to @var{input-method}. -If @var{input-method} is @code{nil}, this function deactivates any input +If @var{input-method} is @code{nil}, this command deactivates any input method for the current buffer. -@end defun +@end deffn @defun read-input-method-name prompt &optional default inhibit-null This function reads an input method name with the minibuffer, prompting @@ -1240,7 +1305,8 @@ @end defvar The fundamental interface to input methods is through the -variable @code{input-method-function}. @xref{Reading One Event}. +variable @code{input-method-function}. @xref{Reading One Event}, +and @ref{Invoking the Input Method}. @node Locales @section Locales @@ -1294,14 +1360,14 @@ @item paper Return a list @code{(@var{width} @var{height})} for the default paper -size measured in milimeters (locale items @code{PAPER_WIDTH} and +size measured in millimeters (locale items @code{PAPER_WIDTH} and @code{PAPER_HEIGHT}). @end table If the system can't provide the requested information, or if @var{item} is not one of those symbols, the value is @code{nil}. All strings in the return value are decoded using -@code{locale-coding-system}. @xref{Locales,,, libc, GNU Libc Manual}, +@code{locale-coding-system}. @xref{Locales,,, libc, The GNU Libc Manual}, for more information about locales and locale items. @end defun
--- a/lispref/objects.texi Sun Dec 28 16:04:37 2003 +0000 +++ b/lispref/objects.texi Sun Dec 28 16:05:28 2003 +0000 @@ -42,7 +42,9 @@ variable, and the type is known by the compiler but not represented in the data. Such type declarations do not exist in Emacs Lisp. A Lisp variable can have any type of value, and it remembers whatever value -you store in it, type and all. +you store in it, type and all. (Actually, a small number of Emacs +Lisp variables can only take on values of a certain type. +@xref{Variables with Restricted Values}.) This chapter describes the purpose, printed representation, and read syntax of each of the standard types in GNU Emacs Lisp. Details on how
--- a/lispref/processes.texi Sun Dec 28 16:04:37 2003 +0000 +++ b/lispref/processes.texi Sun Dec 28 16:05:28 2003 +0000 @@ -676,6 +676,7 @@ @ref{Asynchronous Processes}). @end defun +@anchor{Coding systems for a subprocess} @defun process-coding-system process This function returns a cons cell describing the coding systems in use for decoding output from @var{process} and for encoding input to
--- a/lispref/tips.texi Sun Dec 28 16:04:37 2003 +0000 +++ b/lispref/tips.texi Sun Dec 28 16:05:28 2003 +0000 @@ -647,6 +647,7 @@ This prevents the open-parenthesis from being treated as the start of a defun (@pxref{Defuns,, Defuns, emacs, The GNU Emacs Manual}). +@anchor{Docstring hyperlinks} @item @iftex When a documentation string refers to a Lisp symbol, write it as it
--- a/lispref/variables.texi Sun Dec 28 16:04:37 2003 +0000 +++ b/lispref/variables.texi Sun Dec 28 16:05:28 2003 +0000 @@ -43,6 +43,8 @@ * Future Local Variables:: New kinds of local values we might add some day. * Variable Aliases:: Variables that are aliases for other variables. * File Local Variables:: Handling local variable lists in files. +* Variables with Restricted Values:: Non-constant variables whose value can + @emph{not} be an arbitrary Lisp object. @end menu @node Global Variables @@ -258,19 +260,21 @@ they are localized depending on ``where'' you are in Emacs, rather than localized in time. +@anchor{Definition of max-specpdl-size} @defvar max-specpdl-size @cindex variable limit error @cindex evaluation error @cindex infinite recursion This variable defines the limit on the total number of local variable -bindings and @code{unwind-protect} cleanups (@pxref{Nonlocal Exits}) -that are allowed before signaling an error (with data @code{"Variable -binding depth exceeds max-specpdl-size"}). +bindings and @code{unwind-protect} cleanups (@pxref{Cleanups,, +Cleaning Up from Nonlocal Exits}) that are allowed before signaling an +error (with data @code{"Variable binding depth exceeds +max-specpdl-size"}). This limit, with the associated error when it is exceeded, is one way that Lisp avoids infinite recursion on an ill-defined function. @code{max-lisp-eval-depth} provides another limit on depth of nesting. -@xref{Eval}. +@xref{Definition of max-lisp-eval-depth,, Eval}. The default value is 600. Entry to the Lisp debugger increases the value, if there is little room left, to make sure the debugger itself @@ -1813,6 +1817,41 @@ properties from string values specified in a file's local variables list. +@node Variables with Restricted Values +@section Variables with Restricted Values + + Ordinary Lisp variables can be assigned any value that is a valid +Lisp object. However, certain Lisp variables are not defined in Lisp, +but in C. Most of these variables are defined in the C code using +@code{DEFVAR_LISP}. Like variables defined in Lisp, these can take on +any value. However, some variables are defined using +@code{DEFVAR_INT} or @code{DEFVAR_BOOL}. @xref{Defining Lisp +variables in C,, Writing Emacs Primitives}, in particular the +description of functions of the type @code{syms_of_@var{filename}}, +for a brief discussion of the C implementation. + + Variables of type @code{DEFVAR_BOOL} can only take on the values +@code{nil} or @code{t}. Attempting to assign them any other value +will set them to @code{t}: + +@example +(let ((display-hourglass 5)) + display-hourglass) + @result{} t +@end example + +@defvar byte-boolean-vars +This variable holds a list of all variables of type @code{DEFVAR_BOOL}. +@end defvar + + Variables of type @code{DEFVAR_INT} can only take on integer values. +Attempting to assign them any other value will result in an error: + +@example +(setq window-min-height 5.0) +@error{} Wrong type argument: integerp, 5.0 +@end example + @ignore arch-tag: 5ff62c44-2b51-47bb-99d4-fea5aeec5d3e @end ignore
--- a/src/ChangeLog Sun Dec 28 16:04:37 2003 +0000 +++ b/src/ChangeLog Sun Dec 28 16:05:28 2003 +0000 @@ -1,3 +1,94 @@ +2003-12-28 Kim F. Storm <storm@cua.dk> + + * Makefile.in (eval.o): Depend on dispextern.h. + + * dispnew.c (buffer_posn_from_coords): Fix calculation of dy for + image glyph using image's ascent. + (mode_line_string): Return image glyph as object clicked on. + Adjust y0 for image glyph using image's ascent. + + * dispextern.h (FACE_ID_BITS, MAX_FACE_ID): New defines. + (struct glyph): New members, ascent and descent. Used to save + this glyph's ascent and descent, instead of having. + (struct glyph): Declare member face_id using FACE_ID_BITS. + (find_hot_spot): Add prototype. + + * keyboard.c (Qimage): Remove extern (now in lisp.h). + (QCmap): Declare extern. + (make_lispy_position): When position is inside image hot-spot, + use hot-spot element's id as posn element. + + * lisp.h (IMAGEP): New macro to test for image object type. + (Qimage): Declare extern. + + * macfns.c (Qimage): Remove extern (now in lisp.h). + (valid_image_p, parse_image_spec): Use IMAGEP macro. + + * macterm.c (Qface, Qmouse_face): Remove unused externs. + + * w32fns.c (Qimage): Remove extern (now in lisp.h). + (valid_image_p, parse_image_spec): Use IMAGEP macro. + + * w32menu.c (Qmouse_click, Qevent_kind): Remove unused externs. + + * w32term.c (Qface, Qmouse_face): Remove unused externs. + + * xdisp.c (Qarrow, Qhand, Qtext, Qpointer): New variables for + pointer types. + (Qrelative_width, Qalign_to): Remove unused variables. + (Vvoid_text_area_pointer): Replace Vshow_text_cursor_in_void. + (QCmap, QCpointer, Qrect, Qcircle, Qpoly): New variables for + image maps. + (x_y_to_hpos_vpos): Return glyph relative coordinates through + new dx and dy args. + Remove buffer_only_p arg (always 0). Simplify code accordingly. + (get_glyph_string_clip_rect): Draw cursor using glyph's rather + than row's ascent and height, to get sensible height on tall rows. + (build_desired_tool_bar_string): Remove Qimage extern. + (get_tool_bar_item): Fix call to x_y_to_hpos_vpos. + (produce_image_glyph): Adjust it.ascent to minimum row ascent if + image glyph is alone on the last line. + (append_glyph, append_composite_glyph, produce_image_glyph) + (append_stretch_glyph): Set glyph's ascent and descent. + (on_hot_spot_p): New function to check if position is inside an + rectangular, circular, or polygon-shaped image hot-spot, + (find_hot_spot): New function to search for image hot-spot. + (Flookup_image_map): New defun to search for image hot-spot. + (define_frame_cursor1): New aux function to determine frame pointer. + (note_mode_line_or_margin_highlight, note_mouse_highlight): + Handle `pointer' text property and :pointer image property to + control frame pointer shape. Detect image hot-spots for pointer + and help_echo properties. Use define_frame_cursor1. + (note_mouse_highlight): Use Vvoid_text_area_pointer. + (syms_of_xdisp): Defsubr new defun. Intern and staticpro new variables. + DEFVAR_LISP Vvoid_text_area_pointer instead of Vshow_text_cursor_in_void. + + * xfaces.c (cache_face): Abort if c->size exceeds MAX_FACE_ID. + + * xfns.c (x_set_mouse_color): Remove bogus x_check_errors call. + (Qimage): Remove extern (now in lisp.h). + (valid_image_p, parse_image_spec): Use IMAGEP macro. + + * xmenu.c (show_help_event): Remove unused code. + + * xterm.c (Qface, Qmouse_face): Remove unused externs. + (x_draw_hollow_cursor): Draw cursor using glyph's rather than + row's ascent and descent, to get a sensible height on tall rows. + +2003-12-25 Luc Teirlinck <teirllm@auburn.edu> + + * minibuf.c (Fcompleting_read): Undo previous change. + +2003-12-25 Lars Hansen <larsh@math.ku.dk> + + * dired.c (Fdirectory_files, Fdirectory_files_and_attributes): + Arguments GCPRO'ed in call to file name handler. + +2003-12-25 Thien-Thi Nguyen <ttn@gnu.org> + + * termcap.c (tgetst1): Scan for "%pN"; if all + N are continuous in [1,9], remove all "%pN". + 2003-12-24 Jan Dj,Ad(Brv <jan.h.d@swipnet.se> * gtkutil.c (xg_frame_set_char_size): Call x_wm_set_size_hint.
--- a/src/Makefile.in Sun Dec 28 16:04:37 2003 +0000 +++ b/src/Makefile.in Sun Dec 28 16:05:28 2003 +0000 @@ -1172,7 +1172,7 @@ bytecode.o: bytecode.c buffer.h syntax.h charset.h window.h $(config_h) data.o: data.c buffer.h puresize.h charset.h syssignal.h keyboard.h $(config_h) eval.o: eval.c commands.h keyboard.h blockinput.h atimer.h systime.h \ - $(config_h) + dispextern.h $(config_h) floatfns.o: floatfns.c $(config_h) fns.o: fns.c commands.h $(config_h) frame.h buffer.h charset.h keyboard.h \ frame.h window.h dispextern.h $(INTERVAL_SRC) coding.h md5.h
--- a/src/composite.c Sun Dec 28 16:04:37 2003 +0000 +++ b/src/composite.c Sun Dec 28 16:05:28 2003 +0000 @@ -842,9 +842,12 @@ args[0] = QCtest; args[1] = Qequal; + /* We used to make the hash table weak so that unreferenced + compostions can be garbage-collected. But, usually once + created compositions are repeatedly used in an Emacs session, + and thus it's not worth to save memory in such a way. So, we + make the table not weak. */ args[2] = QCweakness; - /* Fixme: It seems that a weak hash table leads to segfault in GC, - but I have not yet found why. -- handa@m17n.org */ args[3] = Qnil; args[4] = QCsize; args[5] = make_number (311);
--- a/src/dired.c Sun Dec 28 16:04:37 2003 +0000 +++ b/src/dired.c Sun Dec 28 16:05:28 2003 +0000 @@ -359,17 +359,8 @@ call the corresponding file handler. */ handler = Ffind_file_name_handler (directory, Qdirectory_files); if (!NILP (handler)) - { - Lisp_Object args[6]; - - args[0] = handler; - args[1] = Qdirectory_files; - args[2] = directory; - args[3] = full; - args[4] = match; - args[5] = nosort; - return Ffuncall (6, args); - } + return call5 (handler, Qdirectory_files, directory, + full, match, nosort); return directory_files_internal (directory, full, match, nosort, 0, Qnil); } @@ -395,18 +386,8 @@ call the corresponding file handler. */ handler = Ffind_file_name_handler (directory, Qdirectory_files_and_attributes); if (!NILP (handler)) - { - Lisp_Object args[7]; - - args[0] = handler; - args[1] = Qdirectory_files_and_attributes; - args[2] = directory; - args[3] = full; - args[4] = match; - args[5] = nosort; - args[6] = id_format; - return Ffuncall (7, args); - } + return call6 (handler, Qdirectory_files_and_attributes, + directory, full, match, nosort, id_format); return directory_files_internal (directory, full, match, nosort, 1, id_format); }
--- a/src/dispextern.h Sun Dec 28 16:04:37 2003 +0000 +++ b/src/dispextern.h Sun Dec 28 16:05:28 2003 +0000 @@ -321,6 +321,9 @@ /* Width in pixels. */ short pixel_width; + /* Ascent and descent in pixels. */ + short ascent, descent; + /* Vertical offset. If < 0, the glyph is displayed raised, if > 0 the glyph is displayed lowered. */ short voffset; @@ -359,8 +362,10 @@ doesn't have a glyph in a font. */ unsigned glyph_not_available_p : 1; +#define FACE_ID_BITS 21 + /* Face of the glyph. */ - unsigned face_id : 21; + unsigned face_id : FACE_ID_BITS; /* Type of font used to display the character glyph. May be used to determine which set of functions to use to obtain font metrics @@ -1493,6 +1498,7 @@ BASIC_FACE_ID_SENTINEL }; +#define MAX_FACE_ID ((1 << FACE_ID_BITS) - 1) /* A cache of realized faces. Each frame has its own cache because Emacs allows different frame-local face definitions. */ @@ -2536,6 +2542,7 @@ extern void frame_to_window_pixel_xy P_ ((struct window *, int *, int *)); extern void get_glyph_string_clip_rect P_ ((struct glyph_string *, NativeRectangle *nr)); +extern Lisp_Object find_hot_spot P_ ((Lisp_Object, int, int)); extern void note_mouse_highlight P_ ((struct frame *, int, int)); extern void x_clear_window_mouse_face P_ ((struct window *)); extern void cancel_mouse_face P_ ((struct frame *));
--- a/src/dispnew.c Sun Dec 28 16:04:37 2003 +0000 +++ b/src/dispnew.c Sun Dec 28 16:05:28 2003 +0000 @@ -5700,8 +5700,6 @@ struct it it; struct buffer *old_current_buffer = current_buffer; struct text_pos startp; - struct glyph_row *row; - struct image *img; int x0, x1; current_buffer = XBUFFER (w->buffer); @@ -5714,25 +5712,44 @@ move_it_to (&it, -1, x0 + it.first_visible_x, *y, -1, MOVE_TO_X | MOVE_TO_Y); - /* Add extra (default width) columns if clicked after EOL. */ - x1 = max(0, it.current_x + it.pixel_width - it.first_visible_x); - if (x0 > x1) - it.hpos += (x0 - x1) / WINDOW_FRAME_COLUMN_WIDTH (w); - current_buffer = old_current_buffer; *dx = x0 + it.first_visible_x - it.current_x; *dy = *y - it.current_y; + *object = w->buffer; + #ifdef HAVE_WINDOW_SYSTEM - if (it.what == IT_IMAGE - && (img = IMAGE_FROM_ID (it.f, it.image_id)) != NULL - && !NILP (img->spec)) - *object = img->spec; + if (it.what == IT_IMAGE) + { + struct image *img; + if ((img = IMAGE_FROM_ID (it.f, it.image_id)) != NULL + && !NILP (img->spec)) + { + struct glyph_row *row = MATRIX_ROW (w->current_matrix, it.vpos); + struct glyph *glyph; + + if (it.hpos < row->used[TEXT_AREA] + && (glyph = row->glyphs[TEXT_AREA] + it.hpos, + glyph->type == IMAGE_GLYPH)) + { + *dy -= row->ascent - glyph->ascent; + *object = img->spec; + } + } + } else #endif - *object = STRINGP (it.string) ? it.string : w->buffer; + if (STRINGP (it.string)) + *object = it.string; + *pos = it.current; + + /* Add extra (default width) columns if clicked after EOL. */ + x1 = max(0, it.current_x + it.pixel_width - it.first_visible_x); + if (x0 > x1) + it.hpos += (x0 - x1) / WINDOW_FRAME_COLUMN_WIDTH (w); + *x = it.hpos; *y = it.vpos; } @@ -5852,6 +5869,16 @@ { string = glyph->object; *charpos = glyph->charpos; +#ifdef HAVE_WINDOW_SYSTEM + if (glyph->type == IMAGE_GLYPH) + { + struct image *img; + img = IMAGE_FROM_ID (WINDOW_XFRAME (w), glyph->u.img_id); + if (img != NULL) + string = img->spec; + y0 -= row->ascent - glyph->ascent; + } +#endif } else /* Add extra (default width) columns if clicked after EOL. */
--- a/src/keyboard.c Sun Dec 28 16:04:37 2003 +0000 +++ b/src/keyboard.c Sun Dec 28 16:05:28 2003 +0000 @@ -579,7 +579,7 @@ Lisp_Object Qmenu_bar; extern Lisp_Object Qleft_margin, Qright_margin; extern Lisp_Object Qleft_fringe, Qright_fringe; -extern Lisp_Object Qimage; +extern Lisp_Object QCmap; Lisp_Object recursive_edit_unwind (), command_loop (); Lisp_Object Fthis_command_keys (); @@ -5016,6 +5016,19 @@ string = marginal_area_string (w, &rx, &ry, &dx, &dy, part, &charpos); if (STRINGP (string)) object = Fcons (string, make_number (charpos)); +#ifdef HAVE_WINDOW_SYSTEM + else if (IMAGEP (string)) + { + Lisp_Object image_map, hotspot; + object = string; + if ((image_map = Fplist_get (XCDR (object), QCmap), + !NILP (image_map)) + && (hotspot = find_hot_spot (image_map, dx, dy), + CONSP (hotspot)) + && (hotspot = XCDR (hotspot), CONSP (hotspot))) + posn = XCAR (hotspot); + } +#endif } else if (part == ON_LEFT_FRINGE || part == ON_RIGHT_FRINGE) { @@ -5051,8 +5064,19 @@ if (STRINGP (string)) object = Fcons (string, make_number (CHARPOS (p.string_pos))); - else if (CONSP (string) && EQ (XCAR (string), Qimage)) - object = string; +#ifdef HAVE_WINDOW_SYSTEM + else if (IMAGEP (string)) + { + Lisp_Object image_map, hotspot; + object = string; + if ((image_map = Fplist_get (XCDR (object), QCmap), + !NILP (image_map)) + && (hotspot = find_hot_spot (image_map, dx, dy), + CONSP (hotspot)) + && (hotspot = XCDR (hotspot), CONSP (hotspot))) + posn = XCAR (hotspot); + } +#endif } }
--- a/src/lisp.h Sun Dec 28 16:04:37 2003 +0000 +++ b/src/lisp.h Sun Dec 28 16:05:28 2003 +0000 @@ -1381,6 +1381,10 @@ #define GC_FRAMEP(x) GC_PSEUDOVECTORP (x, PVEC_FRAME) #define SUB_CHAR_TABLE_P(x) (CHAR_TABLE_P (x) && NILP (XCHAR_TABLE (x)->top)) + +/* Test for image (image . spec) */ +#define IMAGEP(x) (CONSP (x) && EQ (XCAR (x), Qimage)) + #define GC_EQ(x, y) EQ (x, y) @@ -2283,6 +2287,7 @@ extern Lisp_Object Qinhibit_redisplay, Qdisplay; extern Lisp_Object Qinhibit_eval_during_redisplay; extern Lisp_Object Qmessage_truncate_lines; +extern Lisp_Object Qimage; extern Lisp_Object Vmessage_log_max; extern int message_enable_multibyte; extern Lisp_Object echo_area_buffer[2];
--- a/src/macfns.c Sun Dec 28 16:04:37 2003 +0000 +++ b/src/macfns.c Sun Dec 28 16:05:28 2003 +0000 @@ -3460,11 +3460,6 @@ static struct image_type *image_types; -/* The symbol `image' which is the car of the lists used to represent - images in Lisp. */ - -extern Lisp_Object Qimage; - /* The symbol `xbm' which is used as the type symbol for XBM images. */ Lisp_Object Qxbm; @@ -3543,7 +3538,7 @@ { int valid_p = 0; - if (CONSP (object) && EQ (XCAR (object), Qimage)) + if (IMAGEP (object)) { Lisp_Object symbol = Fplist_get (XCDR (object), QCtype); struct image_type *type = lookup_image_type (symbol); @@ -3633,7 +3628,7 @@ int i; Lisp_Object plist; - if (!CONSP (spec) || !EQ (XCAR (spec), Qimage)) + if (!IMAGEP (spec)) return 0; plist = XCDR (spec);
--- a/src/macterm.c Sun Dec 28 16:04:37 2003 +0000 +++ b/src/macterm.c Sun Dec 28 16:05:28 2003 +0000 @@ -253,8 +253,6 @@ extern Lisp_Object Vx_no_window_manager; -extern Lisp_Object Qface, Qmouse_face; - extern int errno; /* A mask of extra modifier bits to put into every keyboard char. */
--- a/src/minibuf.c Sun Dec 28 16:04:37 2003 +0000 +++ b/src/minibuf.c Sun Dec 28 16:05:28 2003 +0000 @@ -1578,10 +1578,13 @@ Lisp_Object prompt, table, predicate, require_match, initial_input; Lisp_Object hist, def, inherit_input_method; { - Lisp_Object val, histvar, histpos; + Lisp_Object val, histvar, histpos, position; + Lisp_Object init; + int pos = 0; int count = SPECPDL_INDEX (); struct gcpro gcpro1; + init = initial_input; GCPRO1 (def); specbind (Qminibuffer_completion_table, table); @@ -1590,6 +1593,23 @@ EQ (require_match, Qt) ? Qnil : require_match); last_exact_completion = Qnil; + position = Qnil; + if (!NILP (init)) + { + if (CONSP (init)) + { + position = Fcdr (init); + init = Fcar (init); + } + CHECK_STRING (init); + if (!NILP (position)) + { + CHECK_NUMBER (position); + /* Convert to distance from end of input. */ + pos = XINT (position) - SCHARS (init); + } + } + if (SYMBOLP (hist)) { histvar = hist; @@ -1608,7 +1628,7 @@ val = read_minibuf (NILP (require_match) ? Vminibuffer_local_completion_map : Vminibuffer_local_must_match_map, - initial_input, prompt, Qnil, 0, + init, prompt, make_number (pos), 0, histvar, histpos, def, 0, !NILP (inherit_input_method));
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/regex.c Sun Dec 28 16:05:28 2003 +0000 @@ -0,0 +1,6335 @@ +/* Extended regular expression matching and search library, version + 0.12. (Implements POSIX draft P1003.2/D11.2, except for some of the + internationalization features.) + + Copyright (C) 1993,94,95,96,97,98,99,2000 Free Software Foundation, Inc. + + This program 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. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +/* TODO: + - structure the opcode space into opcode+flag. + - merge with glibc's regex.[ch]. + - replace (succeed_n + jump_n + set_number_at) with something that doesn't + need to modify the compiled regexp so that re_match can be reentrant. + - get rid of on_failure_jump_smart by doing the optimization in re_comp + rather than at run-time, so that re_match can be reentrant. +*/ + +/* AIX requires this to be the first thing in the file. */ +#if defined _AIX && !defined REGEX_MALLOC + #pragma alloca +#endif + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#if defined STDC_HEADERS && !defined emacs +# include <stddef.h> +#else +/* We need this for `regex.h', and perhaps for the Emacs include files. */ +# include <sys/types.h> +#endif + +/* Whether to use ISO C Amendment 1 wide char functions. + Those should not be used for Emacs since it uses its own. */ +#if defined _LIBC +#define WIDE_CHAR_SUPPORT 1 +#else +#define WIDE_CHAR_SUPPORT \ + (HAVE_WCTYPE_H && HAVE_WCHAR_H && HAVE_BTOWC && !emacs) +#endif + +/* For platform which support the ISO C amendement 1 functionality we + support user defined character classes. */ +#if WIDE_CHAR_SUPPORT +/* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>. */ +# include <wchar.h> +# include <wctype.h> +#endif + +#ifdef _LIBC +/* We have to keep the namespace clean. */ +# define regfree(preg) __regfree (preg) +# define regexec(pr, st, nm, pm, ef) __regexec (pr, st, nm, pm, ef) +# define regcomp(preg, pattern, cflags) __regcomp (preg, pattern, cflags) +# define regerror(errcode, preg, errbuf, errbuf_size) \ + __regerror(errcode, preg, errbuf, errbuf_size) +# define re_set_registers(bu, re, nu, st, en) \ + __re_set_registers (bu, re, nu, st, en) +# define re_match_2(bufp, string1, size1, string2, size2, pos, regs, stop) \ + __re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) +# define re_match(bufp, string, size, pos, regs) \ + __re_match (bufp, string, size, pos, regs) +# define re_search(bufp, string, size, startpos, range, regs) \ + __re_search (bufp, string, size, startpos, range, regs) +# define re_compile_pattern(pattern, length, bufp) \ + __re_compile_pattern (pattern, length, bufp) +# define re_set_syntax(syntax) __re_set_syntax (syntax) +# define re_search_2(bufp, st1, s1, st2, s2, startpos, range, regs, stop) \ + __re_search_2 (bufp, st1, s1, st2, s2, startpos, range, regs, stop) +# define re_compile_fastmap(bufp) __re_compile_fastmap (bufp) + +/* Make sure we call libc's function even if the user overrides them. */ +# define btowc __btowc +# define iswctype __iswctype +# define wctype __wctype + +# define WEAK_ALIAS(a,b) weak_alias (a, b) + +/* We are also using some library internals. */ +# include <locale/localeinfo.h> +# include <locale/elem-hash.h> +# include <langinfo.h> +#else +# define WEAK_ALIAS(a,b) +#endif + +/* This is for other GNU distributions with internationalized messages. */ +#if HAVE_LIBINTL_H || defined _LIBC +# include <libintl.h> +#else +# define gettext(msgid) (msgid) +#endif + +#ifndef gettext_noop +/* This define is so xgettext can find the internationalizable + strings. */ +# define gettext_noop(String) String +#endif + +/* The `emacs' switch turns on certain matching commands + that make sense only in Emacs. */ +#ifdef emacs + +# include "lisp.h" +# include "buffer.h" + +/* Make syntax table lookup grant data in gl_state. */ +# define SYNTAX_ENTRY_VIA_PROPERTY + +# include "syntax.h" +# include "charset.h" +# include "category.h" + +# ifdef malloc +# undef malloc +# endif +# define malloc xmalloc +# ifdef realloc +# undef realloc +# endif +# define realloc xrealloc +# ifdef free +# undef free +# endif +# define free xfree + +/* Converts the pointer to the char to BEG-based offset from the start. */ +# define PTR_TO_OFFSET(d) POS_AS_IN_BUFFER (POINTER_TO_OFFSET (d)) +# define POS_AS_IN_BUFFER(p) ((p) + (NILP (re_match_object) || BUFFERP (re_match_object))) + +# define RE_MULTIBYTE_P(bufp) ((bufp)->multibyte) +# define RE_STRING_CHAR(p, s) \ + (multibyte ? (STRING_CHAR (p, s)) : (*(p))) +# define RE_STRING_CHAR_AND_LENGTH(p, s, len) \ + (multibyte ? (STRING_CHAR_AND_LENGTH (p, s, len)) : ((len) = 1, *(p))) + +/* Set C a (possibly multibyte) character before P. P points into a + string which is the virtual concatenation of STR1 (which ends at + END1) or STR2 (which ends at END2). */ +# define GET_CHAR_BEFORE_2(c, p, str1, end1, str2, end2) \ + do { \ + if (multibyte) \ + { \ + re_char *dtemp = (p) == (str2) ? (end1) : (p); \ + re_char *dlimit = ((p) > (str2) && (p) <= (end2)) ? (str2) : (str1); \ + re_char *d0 = dtemp; \ + PREV_CHAR_BOUNDARY (d0, dlimit); \ + c = STRING_CHAR (d0, dtemp - d0); \ + } \ + else \ + (c = ((p) == (str2) ? (end1) : (p))[-1]); \ + } while (0) + + +#else /* not emacs */ + +/* If we are not linking with Emacs proper, + we can't use the relocating allocator + even if config.h says that we can. */ +# undef REL_ALLOC + +# if defined STDC_HEADERS || defined _LIBC +# include <stdlib.h> +# else +char *malloc (); +char *realloc (); +# endif + +/* When used in Emacs's lib-src, we need to get bzero and bcopy somehow. + If nothing else has been done, use the method below. */ +# ifdef INHIBIT_STRING_HEADER +# if !(defined HAVE_BZERO && defined HAVE_BCOPY) +# if !defined bzero && !defined bcopy +# undef INHIBIT_STRING_HEADER +# endif +# endif +# endif + +/* This is the normal way of making sure we have memcpy, memcmp and bzero. + This is used in most programs--a few other programs avoid this + by defining INHIBIT_STRING_HEADER. */ +# ifndef INHIBIT_STRING_HEADER +# if defined HAVE_STRING_H || defined STDC_HEADERS || defined _LIBC +# include <string.h> +# ifndef bzero +# ifndef _LIBC +# define bzero(s, n) (memset (s, '\0', n), (s)) +# else +# define bzero(s, n) __bzero (s, n) +# endif +# endif +# else +# include <strings.h> +# ifndef memcmp +# define memcmp(s1, s2, n) bcmp (s1, s2, n) +# endif +# ifndef memcpy +# define memcpy(d, s, n) (bcopy (s, d, n), (d)) +# endif +# endif +# endif + +/* Define the syntax stuff for \<, \>, etc. */ + +/* Sword must be nonzero for the wordchar pattern commands in re_match_2. */ +enum syntaxcode { Swhitespace = 0, Sword = 1 }; + +# ifdef SWITCH_ENUM_BUG +# define SWITCH_ENUM_CAST(x) ((int)(x)) +# else +# define SWITCH_ENUM_CAST(x) (x) +# endif + +/* Dummy macros for non-Emacs environments. */ +# define BASE_LEADING_CODE_P(c) (0) +# define CHAR_CHARSET(c) 0 +# define CHARSET_LEADING_CODE_BASE(c) 0 +# define MAX_MULTIBYTE_LENGTH 1 +# define RE_MULTIBYTE_P(x) 0 +# define WORD_BOUNDARY_P(c1, c2) (0) +# define CHAR_HEAD_P(p) (1) +# define SINGLE_BYTE_CHAR_P(c) (1) +# define SAME_CHARSET_P(c1, c2) (1) +# define MULTIBYTE_FORM_LENGTH(p, s) (1) +# define PREV_CHAR_BOUNDARY(p, limit) ((p)--) +# define STRING_CHAR(p, s) (*(p)) +# define RE_STRING_CHAR STRING_CHAR +# define CHAR_STRING(c, s) (*(s) = (c), 1) +# define STRING_CHAR_AND_LENGTH(p, s, actual_len) ((actual_len) = 1, *(p)) +# define RE_STRING_CHAR_AND_LENGTH STRING_CHAR_AND_LENGTH +# define GET_CHAR_BEFORE_2(c, p, str1, end1, str2, end2) \ + (c = ((p) == (str2) ? *((end1) - 1) : *((p) - 1))) +# define MAKE_CHAR(charset, c1, c2) (c1) +#endif /* not emacs */ + +#ifndef RE_TRANSLATE +# define RE_TRANSLATE(TBL, C) ((unsigned char)(TBL)[C]) +# define RE_TRANSLATE_P(TBL) (TBL) +#endif + +/* Get the interface, including the syntax bits. */ +#include "regex.h" + +/* isalpha etc. are used for the character classes. */ +#include <ctype.h> + +#ifdef emacs + +/* 1 if C is an ASCII character. */ +# define IS_REAL_ASCII(c) ((c) < 0200) + +/* 1 if C is a unibyte character. */ +# define ISUNIBYTE(c) (SINGLE_BYTE_CHAR_P ((c))) + +/* The Emacs definitions should not be directly affected by locales. */ + +/* In Emacs, these are only used for single-byte characters. */ +# define ISDIGIT(c) ((c) >= '0' && (c) <= '9') +# define ISCNTRL(c) ((c) < ' ') +# define ISXDIGIT(c) (((c) >= '0' && (c) <= '9') \ + || ((c) >= 'a' && (c) <= 'f') \ + || ((c) >= 'A' && (c) <= 'F')) + +/* This is only used for single-byte characters. */ +# define ISBLANK(c) ((c) == ' ' || (c) == '\t') + +/* The rest must handle multibyte characters. */ + +# define ISGRAPH(c) (SINGLE_BYTE_CHAR_P (c) \ + ? (c) > ' ' && !((c) >= 0177 && (c) <= 0237) \ + : 1) + +# define ISPRINT(c) (SINGLE_BYTE_CHAR_P (c) \ + ? (c) >= ' ' && !((c) >= 0177 && (c) <= 0237) \ + : 1) + +# define ISALNUM(c) (IS_REAL_ASCII (c) \ + ? (((c) >= 'a' && (c) <= 'z') \ + || ((c) >= 'A' && (c) <= 'Z') \ + || ((c) >= '0' && (c) <= '9')) \ + : SYNTAX (c) == Sword) + +# define ISALPHA(c) (IS_REAL_ASCII (c) \ + ? (((c) >= 'a' && (c) <= 'z') \ + || ((c) >= 'A' && (c) <= 'Z')) \ + : SYNTAX (c) == Sword) + +# define ISLOWER(c) (LOWERCASEP (c)) + +# define ISPUNCT(c) (IS_REAL_ASCII (c) \ + ? ((c) > ' ' && (c) < 0177 \ + && !(((c) >= 'a' && (c) <= 'z') \ + || ((c) >= 'A' && (c) <= 'Z') \ + || ((c) >= '0' && (c) <= '9'))) \ + : SYNTAX (c) != Sword) + +# define ISSPACE(c) (SYNTAX (c) == Swhitespace) + +# define ISUPPER(c) (UPPERCASEP (c)) + +# define ISWORD(c) (SYNTAX (c) == Sword) + +#else /* not emacs */ + +/* Jim Meyering writes: + + "... Some ctype macros are valid only for character codes that + isascii says are ASCII (SGI's IRIX-4.0.5 is one such system --when + using /bin/cc or gcc but without giving an ansi option). So, all + ctype uses should be through macros like ISPRINT... If + STDC_HEADERS is defined, then autoconf has verified that the ctype + macros don't need to be guarded with references to isascii. ... + Defining isascii to 1 should let any compiler worth its salt + eliminate the && through constant folding." + Solaris defines some of these symbols so we must undefine them first. */ + +# undef ISASCII +# if defined STDC_HEADERS || (!defined isascii && !defined HAVE_ISASCII) +# define ISASCII(c) 1 +# else +# define ISASCII(c) isascii(c) +# endif + +/* 1 if C is an ASCII character. */ +# define IS_REAL_ASCII(c) ((c) < 0200) + +/* This distinction is not meaningful, except in Emacs. */ +# define ISUNIBYTE(c) 1 + +# ifdef isblank +# define ISBLANK(c) (ISASCII (c) && isblank (c)) +# else +# define ISBLANK(c) ((c) == ' ' || (c) == '\t') +# endif +# ifdef isgraph +# define ISGRAPH(c) (ISASCII (c) && isgraph (c)) +# else +# define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c)) +# endif + +# undef ISPRINT +# define ISPRINT(c) (ISASCII (c) && isprint (c)) +# define ISDIGIT(c) (ISASCII (c) && isdigit (c)) +# define ISALNUM(c) (ISASCII (c) && isalnum (c)) +# define ISALPHA(c) (ISASCII (c) && isalpha (c)) +# define ISCNTRL(c) (ISASCII (c) && iscntrl (c)) +# define ISLOWER(c) (ISASCII (c) && islower (c)) +# define ISPUNCT(c) (ISASCII (c) && ispunct (c)) +# define ISSPACE(c) (ISASCII (c) && isspace (c)) +# define ISUPPER(c) (ISASCII (c) && isupper (c)) +# define ISXDIGIT(c) (ISASCII (c) && isxdigit (c)) + +# define ISWORD(c) ISALPHA(c) + +# ifdef _tolower +# define TOLOWER(c) _tolower(c) +# else +# define TOLOWER(c) tolower(c) +# endif + +/* How many characters in the character set. */ +# define CHAR_SET_SIZE 256 + +# ifdef SYNTAX_TABLE + +extern char *re_syntax_table; + +# else /* not SYNTAX_TABLE */ + +static char re_syntax_table[CHAR_SET_SIZE]; + +static void +init_syntax_once () +{ + register int c; + static int done = 0; + + if (done) + return; + + bzero (re_syntax_table, sizeof re_syntax_table); + + for (c = 0; c < CHAR_SET_SIZE; ++c) + if (ISALNUM (c)) + re_syntax_table[c] = Sword; + + re_syntax_table['_'] = Sword; + + done = 1; +} + +# endif /* not SYNTAX_TABLE */ + +# define SYNTAX(c) re_syntax_table[(c)] + +#endif /* not emacs */ + +#ifndef NULL +# define NULL (void *)0 +#endif + +/* We remove any previous definition of `SIGN_EXTEND_CHAR', + since ours (we hope) works properly with all combinations of + machines, compilers, `char' and `unsigned char' argument types. + (Per Bothner suggested the basic approach.) */ +#undef SIGN_EXTEND_CHAR +#if __STDC__ +# define SIGN_EXTEND_CHAR(c) ((signed char) (c)) +#else /* not __STDC__ */ +/* As in Harbison and Steele. */ +# define SIGN_EXTEND_CHAR(c) ((((unsigned char) (c)) ^ 128) - 128) +#endif + +/* Should we use malloc or alloca? If REGEX_MALLOC is not defined, we + use `alloca' instead of `malloc'. This is because using malloc in + re_search* or re_match* could cause memory leaks when C-g is used in + Emacs; also, malloc is slower and causes storage fragmentation. On + the other hand, malloc is more portable, and easier to debug. + + Because we sometimes use alloca, some routines have to be macros, + not functions -- `alloca'-allocated space disappears at the end of the + function it is called in. */ + +#ifdef REGEX_MALLOC + +# define REGEX_ALLOCATE malloc +# define REGEX_REALLOCATE(source, osize, nsize) realloc (source, nsize) +# define REGEX_FREE free + +#else /* not REGEX_MALLOC */ + +/* Emacs already defines alloca, sometimes. */ +# ifndef alloca + +/* Make alloca work the best possible way. */ +# ifdef __GNUC__ +# define alloca __builtin_alloca +# else /* not __GNUC__ */ +# if HAVE_ALLOCA_H +# include <alloca.h> +# endif /* HAVE_ALLOCA_H */ +# endif /* not __GNUC__ */ + +# endif /* not alloca */ + +# define REGEX_ALLOCATE alloca + +/* Assumes a `char *destination' variable. */ +# define REGEX_REALLOCATE(source, osize, nsize) \ + (destination = (char *) alloca (nsize), \ + memcpy (destination, source, osize)) + +/* No need to do anything to free, after alloca. */ +# define REGEX_FREE(arg) ((void)0) /* Do nothing! But inhibit gcc warning. */ + +#endif /* not REGEX_MALLOC */ + +/* Define how to allocate the failure stack. */ + +#if defined REL_ALLOC && defined REGEX_MALLOC + +# define REGEX_ALLOCATE_STACK(size) \ + r_alloc (&failure_stack_ptr, (size)) +# define REGEX_REALLOCATE_STACK(source, osize, nsize) \ + r_re_alloc (&failure_stack_ptr, (nsize)) +# define REGEX_FREE_STACK(ptr) \ + r_alloc_free (&failure_stack_ptr) + +#else /* not using relocating allocator */ + +# ifdef REGEX_MALLOC + +# define REGEX_ALLOCATE_STACK malloc +# define REGEX_REALLOCATE_STACK(source, osize, nsize) realloc (source, nsize) +# define REGEX_FREE_STACK free + +# else /* not REGEX_MALLOC */ + +# define REGEX_ALLOCATE_STACK alloca + +# define REGEX_REALLOCATE_STACK(source, osize, nsize) \ + REGEX_REALLOCATE (source, osize, nsize) +/* No need to explicitly free anything. */ +# define REGEX_FREE_STACK(arg) ((void)0) + +# endif /* not REGEX_MALLOC */ +#endif /* not using relocating allocator */ + + +/* True if `size1' is non-NULL and PTR is pointing anywhere inside + `string1' or just past its end. This works if PTR is NULL, which is + a good thing. */ +#define FIRST_STRING_P(ptr) \ + (size1 && string1 <= (ptr) && (ptr) <= string1 + size1) + +/* (Re)Allocate N items of type T using malloc, or fail. */ +#define TALLOC(n, t) ((t *) malloc ((n) * sizeof (t))) +#define RETALLOC(addr, n, t) ((addr) = (t *) realloc (addr, (n) * sizeof (t))) +#define RETALLOC_IF(addr, n, t) \ + if (addr) RETALLOC((addr), (n), t); else (addr) = TALLOC ((n), t) +#define REGEX_TALLOC(n, t) ((t *) REGEX_ALLOCATE ((n) * sizeof (t))) + +#define BYTEWIDTH 8 /* In bits. */ + +#define STREQ(s1, s2) ((strcmp (s1, s2) == 0)) + +#undef MAX +#undef MIN +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +/* Type of source-pattern and string chars. */ +typedef const unsigned char re_char; + +typedef char boolean; +#define false 0 +#define true 1 + +static int re_match_2_internal _RE_ARGS ((struct re_pattern_buffer *bufp, + re_char *string1, int size1, + re_char *string2, int size2, + int pos, + struct re_registers *regs, + int stop)); + +/* These are the command codes that appear in compiled regular + expressions. Some opcodes are followed by argument bytes. A + command code can specify any interpretation whatsoever for its + arguments. Zero bytes may appear in the compiled regular expression. */ + +typedef enum +{ + no_op = 0, + + /* Succeed right away--no more backtracking. */ + succeed, + + /* Followed by one byte giving n, then by n literal bytes. */ + exactn, + + /* Matches any (more or less) character. */ + anychar, + + /* Matches any one char belonging to specified set. First + following byte is number of bitmap bytes. Then come bytes + for a bitmap saying which chars are in. Bits in each byte + are ordered low-bit-first. A character is in the set if its + bit is 1. A character too large to have a bit in the map is + automatically not in the set. + + If the length byte has the 0x80 bit set, then that stuff + is followed by a range table: + 2 bytes of flags for character sets (low 8 bits, high 8 bits) + See RANGE_TABLE_WORK_BITS below. + 2 bytes, the number of pairs that follow (upto 32767) + pairs, each 2 multibyte characters, + each multibyte character represented as 3 bytes. */ + charset, + + /* Same parameters as charset, but match any character that is + not one of those specified. */ + charset_not, + + /* Start remembering the text that is matched, for storing in a + register. Followed by one byte with the register number, in + the range 0 to one less than the pattern buffer's re_nsub + field. */ + start_memory, + + /* Stop remembering the text that is matched and store it in a + memory register. Followed by one byte with the register + number, in the range 0 to one less than `re_nsub' in the + pattern buffer. */ + stop_memory, + + /* Match a duplicate of something remembered. Followed by one + byte containing the register number. */ + duplicate, + + /* Fail unless at beginning of line. */ + begline, + + /* Fail unless at end of line. */ + endline, + + /* Succeeds if at beginning of buffer (if emacs) or at beginning + of string to be matched (if not). */ + begbuf, + + /* Analogously, for end of buffer/string. */ + endbuf, + + /* Followed by two byte relative address to which to jump. */ + jump, + + /* Followed by two-byte relative address of place to resume at + in case of failure. */ + on_failure_jump, + + /* Like on_failure_jump, but pushes a placeholder instead of the + current string position when executed. */ + on_failure_keep_string_jump, + + /* Just like `on_failure_jump', except that it checks that we + don't get stuck in an infinite loop (matching an empty string + indefinitely). */ + on_failure_jump_loop, + + /* Just like `on_failure_jump_loop', except that it checks for + a different kind of loop (the kind that shows up with non-greedy + operators). This operation has to be immediately preceded + by a `no_op'. */ + on_failure_jump_nastyloop, + + /* A smart `on_failure_jump' used for greedy * and + operators. + It analyses the loop before which it is put and if the + loop does not require backtracking, it changes itself to + `on_failure_keep_string_jump' and short-circuits the loop, + else it just defaults to changing itself into `on_failure_jump'. + It assumes that it is pointing to just past a `jump'. */ + on_failure_jump_smart, + + /* Followed by two-byte relative address and two-byte number n. + After matching N times, jump to the address upon failure. + Does not work if N starts at 0: use on_failure_jump_loop + instead. */ + succeed_n, + + /* Followed by two-byte relative address, and two-byte number n. + Jump to the address N times, then fail. */ + jump_n, + + /* Set the following two-byte relative address to the + subsequent two-byte number. The address *includes* the two + bytes of number. */ + set_number_at, + + wordbeg, /* Succeeds if at word beginning. */ + wordend, /* Succeeds if at word end. */ + + wordbound, /* Succeeds if at a word boundary. */ + notwordbound, /* Succeeds if not at a word boundary. */ + + /* Matches any character whose syntax is specified. Followed by + a byte which contains a syntax code, e.g., Sword. */ + syntaxspec, + + /* Matches any character whose syntax is not that specified. */ + notsyntaxspec + +#ifdef emacs + ,before_dot, /* Succeeds if before point. */ + at_dot, /* Succeeds if at point. */ + after_dot, /* Succeeds if after point. */ + + /* Matches any character whose category-set contains the specified + category. The operator is followed by a byte which contains a + category code (mnemonic ASCII character). */ + categoryspec, + + /* Matches any character whose category-set does not contain the + specified category. The operator is followed by a byte which + contains the category code (mnemonic ASCII character). */ + notcategoryspec +#endif /* emacs */ +} re_opcode_t; + +/* Common operations on the compiled pattern. */ + +/* Store NUMBER in two contiguous bytes starting at DESTINATION. */ + +#define STORE_NUMBER(destination, number) \ + do { \ + (destination)[0] = (number) & 0377; \ + (destination)[1] = (number) >> 8; \ + } while (0) + +/* Same as STORE_NUMBER, except increment DESTINATION to + the byte after where the number is stored. Therefore, DESTINATION + must be an lvalue. */ + +#define STORE_NUMBER_AND_INCR(destination, number) \ + do { \ + STORE_NUMBER (destination, number); \ + (destination) += 2; \ + } while (0) + +/* Put into DESTINATION a number stored in two contiguous bytes starting + at SOURCE. */ + +#define EXTRACT_NUMBER(destination, source) \ + do { \ + (destination) = *(source) & 0377; \ + (destination) += SIGN_EXTEND_CHAR (*((source) + 1)) << 8; \ + } while (0) + +#ifdef DEBUG +static void extract_number _RE_ARGS ((int *dest, re_char *source)); +static void +extract_number (dest, source) + int *dest; + re_char *source; +{ + int temp = SIGN_EXTEND_CHAR (*(source + 1)); + *dest = *source & 0377; + *dest += temp << 8; +} + +# ifndef EXTRACT_MACROS /* To debug the macros. */ +# undef EXTRACT_NUMBER +# define EXTRACT_NUMBER(dest, src) extract_number (&dest, src) +# endif /* not EXTRACT_MACROS */ + +#endif /* DEBUG */ + +/* Same as EXTRACT_NUMBER, except increment SOURCE to after the number. + SOURCE must be an lvalue. */ + +#define EXTRACT_NUMBER_AND_INCR(destination, source) \ + do { \ + EXTRACT_NUMBER (destination, source); \ + (source) += 2; \ + } while (0) + +#ifdef DEBUG +static void extract_number_and_incr _RE_ARGS ((int *destination, + re_char **source)); +static void +extract_number_and_incr (destination, source) + int *destination; + re_char **source; +{ + extract_number (destination, *source); + *source += 2; +} + +# ifndef EXTRACT_MACROS +# undef EXTRACT_NUMBER_AND_INCR +# define EXTRACT_NUMBER_AND_INCR(dest, src) \ + extract_number_and_incr (&dest, &src) +# endif /* not EXTRACT_MACROS */ + +#endif /* DEBUG */ + +/* Store a multibyte character in three contiguous bytes starting + DESTINATION, and increment DESTINATION to the byte after where the + character is stored. Therefore, DESTINATION must be an lvalue. */ + +#define STORE_CHARACTER_AND_INCR(destination, character) \ + do { \ + (destination)[0] = (character) & 0377; \ + (destination)[1] = ((character) >> 8) & 0377; \ + (destination)[2] = (character) >> 16; \ + (destination) += 3; \ + } while (0) + +/* Put into DESTINATION a character stored in three contiguous bytes + starting at SOURCE. */ + +#define EXTRACT_CHARACTER(destination, source) \ + do { \ + (destination) = ((source)[0] \ + | ((source)[1] << 8) \ + | ((source)[2] << 16)); \ + } while (0) + + +/* Macros for charset. */ + +/* Size of bitmap of charset P in bytes. P is a start of charset, + i.e. *P is (re_opcode_t) charset or (re_opcode_t) charset_not. */ +#define CHARSET_BITMAP_SIZE(p) ((p)[1] & 0x7F) + +/* Nonzero if charset P has range table. */ +#define CHARSET_RANGE_TABLE_EXISTS_P(p) ((p)[1] & 0x80) + +/* Return the address of range table of charset P. But not the start + of table itself, but the before where the number of ranges is + stored. `2 +' means to skip re_opcode_t and size of bitmap, + and the 2 bytes of flags at the start of the range table. */ +#define CHARSET_RANGE_TABLE(p) (&(p)[4 + CHARSET_BITMAP_SIZE (p)]) + +/* Extract the bit flags that start a range table. */ +#define CHARSET_RANGE_TABLE_BITS(p) \ + ((p)[2 + CHARSET_BITMAP_SIZE (p)] \ + + (p)[3 + CHARSET_BITMAP_SIZE (p)] * 0x100) + +/* Test if C is listed in the bitmap of charset P. */ +#define CHARSET_LOOKUP_BITMAP(p, c) \ + ((c) < CHARSET_BITMAP_SIZE (p) * BYTEWIDTH \ + && (p)[2 + (c) / BYTEWIDTH] & (1 << ((c) % BYTEWIDTH))) + +/* Return the address of end of RANGE_TABLE. COUNT is number of + ranges (which is a pair of (start, end)) in the RANGE_TABLE. `* 2' + is start of range and end of range. `* 3' is size of each start + and end. */ +#define CHARSET_RANGE_TABLE_END(range_table, count) \ + ((range_table) + (count) * 2 * 3) + +/* Test if C is in RANGE_TABLE. A flag NOT is negated if C is in. + COUNT is number of ranges in RANGE_TABLE. */ +#define CHARSET_LOOKUP_RANGE_TABLE_RAW(not, c, range_table, count) \ + do \ + { \ + re_wchar_t range_start, range_end; \ + re_char *p; \ + re_char *range_table_end \ + = CHARSET_RANGE_TABLE_END ((range_table), (count)); \ + \ + for (p = (range_table); p < range_table_end; p += 2 * 3) \ + { \ + EXTRACT_CHARACTER (range_start, p); \ + EXTRACT_CHARACTER (range_end, p + 3); \ + \ + if (range_start <= (c) && (c) <= range_end) \ + { \ + (not) = !(not); \ + break; \ + } \ + } \ + } \ + while (0) + +/* Test if C is in range table of CHARSET. The flag NOT is negated if + C is listed in it. */ +#define CHARSET_LOOKUP_RANGE_TABLE(not, c, charset) \ + do \ + { \ + /* Number of ranges in range table. */ \ + int count; \ + re_char *range_table = CHARSET_RANGE_TABLE (charset); \ + \ + EXTRACT_NUMBER_AND_INCR (count, range_table); \ + CHARSET_LOOKUP_RANGE_TABLE_RAW ((not), (c), range_table, count); \ + } \ + while (0) + +/* If DEBUG is defined, Regex prints many voluminous messages about what + it is doing (if the variable `debug' is nonzero). If linked with the + main program in `iregex.c', you can enter patterns and strings + interactively. And if linked with the main program in `main.c' and + the other test files, you can run the already-written tests. */ + +#ifdef DEBUG + +/* We use standard I/O for debugging. */ +# include <stdio.h> + +/* It is useful to test things that ``must'' be true when debugging. */ +# include <assert.h> + +static int debug = -100000; + +# define DEBUG_STATEMENT(e) e +# define DEBUG_PRINT1(x) if (debug > 0) printf (x) +# define DEBUG_PRINT2(x1, x2) if (debug > 0) printf (x1, x2) +# define DEBUG_PRINT3(x1, x2, x3) if (debug > 0) printf (x1, x2, x3) +# define DEBUG_PRINT4(x1, x2, x3, x4) if (debug > 0) printf (x1, x2, x3, x4) +# define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) \ + if (debug > 0) print_partial_compiled_pattern (s, e) +# define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2) \ + if (debug > 0) print_double_string (w, s1, sz1, s2, sz2) + + +/* Print the fastmap in human-readable form. */ + +void +print_fastmap (fastmap) + char *fastmap; +{ + unsigned was_a_range = 0; + unsigned i = 0; + + while (i < (1 << BYTEWIDTH)) + { + if (fastmap[i++]) + { + was_a_range = 0; + putchar (i - 1); + while (i < (1 << BYTEWIDTH) && fastmap[i]) + { + was_a_range = 1; + i++; + } + if (was_a_range) + { + printf ("-"); + putchar (i - 1); + } + } + } + putchar ('\n'); +} + + +/* Print a compiled pattern string in human-readable form, starting at + the START pointer into it and ending just before the pointer END. */ + +void +print_partial_compiled_pattern (start, end) + re_char *start; + re_char *end; +{ + int mcnt, mcnt2; + re_char *p = start; + re_char *pend = end; + + if (start == NULL) + { + fprintf (stderr, "(null)\n"); + return; + } + + /* Loop over pattern commands. */ + while (p < pend) + { + fprintf (stderr, "%d:\t", p - start); + + switch ((re_opcode_t) *p++) + { + case no_op: + fprintf (stderr, "/no_op"); + break; + + case succeed: + fprintf (stderr, "/succeed"); + break; + + case exactn: + mcnt = *p++; + fprintf (stderr, "/exactn/%d", mcnt); + do + { + fprintf (stderr, "/%c", *p++); + } + while (--mcnt); + break; + + case start_memory: + fprintf (stderr, "/start_memory/%d", *p++); + break; + + case stop_memory: + fprintf (stderr, "/stop_memory/%d", *p++); + break; + + case duplicate: + fprintf (stderr, "/duplicate/%d", *p++); + break; + + case anychar: + fprintf (stderr, "/anychar"); + break; + + case charset: + case charset_not: + { + register int c, last = -100; + register int in_range = 0; + int length = CHARSET_BITMAP_SIZE (p - 1); + int has_range_table = CHARSET_RANGE_TABLE_EXISTS_P (p - 1); + + fprintf (stderr, "/charset [%s", + (re_opcode_t) *(p - 1) == charset_not ? "^" : ""); + + if (p + *p >= pend) + fprintf (stderr, " !extends past end of pattern! "); + + for (c = 0; c < 256; c++) + if (c / 8 < length + && (p[1 + (c/8)] & (1 << (c % 8)))) + { + /* Are we starting a range? */ + if (last + 1 == c && ! in_range) + { + fprintf (stderr, "-"); + in_range = 1; + } + /* Have we broken a range? */ + else if (last + 1 != c && in_range) + { + fprintf (stderr, "%c", last); + in_range = 0; + } + + if (! in_range) + fprintf (stderr, "%c", c); + + last = c; + } + + if (in_range) + fprintf (stderr, "%c", last); + + fprintf (stderr, "]"); + + p += 1 + length; + + if (has_range_table) + { + int count; + fprintf (stderr, "has-range-table"); + + /* ??? Should print the range table; for now, just skip it. */ + p += 2; /* skip range table bits */ + EXTRACT_NUMBER_AND_INCR (count, p); + p = CHARSET_RANGE_TABLE_END (p, count); + } + } + break; + + case begline: + fprintf (stderr, "/begline"); + break; + + case endline: + fprintf (stderr, "/endline"); + break; + + case on_failure_jump: + extract_number_and_incr (&mcnt, &p); + fprintf (stderr, "/on_failure_jump to %d", p + mcnt - start); + break; + + case on_failure_keep_string_jump: + extract_number_and_incr (&mcnt, &p); + fprintf (stderr, "/on_failure_keep_string_jump to %d", p + mcnt - start); + break; + + case on_failure_jump_nastyloop: + extract_number_and_incr (&mcnt, &p); + fprintf (stderr, "/on_failure_jump_nastyloop to %d", p + mcnt - start); + break; + + case on_failure_jump_loop: + extract_number_and_incr (&mcnt, &p); + fprintf (stderr, "/on_failure_jump_loop to %d", p + mcnt - start); + break; + + case on_failure_jump_smart: + extract_number_and_incr (&mcnt, &p); + fprintf (stderr, "/on_failure_jump_smart to %d", p + mcnt - start); + break; + + case jump: + extract_number_and_incr (&mcnt, &p); + fprintf (stderr, "/jump to %d", p + mcnt - start); + break; + + case succeed_n: + extract_number_and_incr (&mcnt, &p); + extract_number_and_incr (&mcnt2, &p); + fprintf (stderr, "/succeed_n to %d, %d times", p - 2 + mcnt - start, mcnt2); + break; + + case jump_n: + extract_number_and_incr (&mcnt, &p); + extract_number_and_incr (&mcnt2, &p); + fprintf (stderr, "/jump_n to %d, %d times", p - 2 + mcnt - start, mcnt2); + break; + + case set_number_at: + extract_number_and_incr (&mcnt, &p); + extract_number_and_incr (&mcnt2, &p); + fprintf (stderr, "/set_number_at location %d to %d", p - 2 + mcnt - start, mcnt2); + break; + + case wordbound: + fprintf (stderr, "/wordbound"); + break; + + case notwordbound: + fprintf (stderr, "/notwordbound"); + break; + + case wordbeg: + fprintf (stderr, "/wordbeg"); + break; + + case wordend: + fprintf (stderr, "/wordend"); + + case syntaxspec: + fprintf (stderr, "/syntaxspec"); + mcnt = *p++; + fprintf (stderr, "/%d", mcnt); + break; + + case notsyntaxspec: + fprintf (stderr, "/notsyntaxspec"); + mcnt = *p++; + fprintf (stderr, "/%d", mcnt); + break; + +# ifdef emacs + case before_dot: + fprintf (stderr, "/before_dot"); + break; + + case at_dot: + fprintf (stderr, "/at_dot"); + break; + + case after_dot: + fprintf (stderr, "/after_dot"); + break; + + case categoryspec: + fprintf (stderr, "/categoryspec"); + mcnt = *p++; + fprintf (stderr, "/%d", mcnt); + break; + + case notcategoryspec: + fprintf (stderr, "/notcategoryspec"); + mcnt = *p++; + fprintf (stderr, "/%d", mcnt); + break; +# endif /* emacs */ + + case begbuf: + fprintf (stderr, "/begbuf"); + break; + + case endbuf: + fprintf (stderr, "/endbuf"); + break; + + default: + fprintf (stderr, "?%d", *(p-1)); + } + + fprintf (stderr, "\n"); + } + + fprintf (stderr, "%d:\tend of pattern.\n", p - start); +} + + +void +print_compiled_pattern (bufp) + struct re_pattern_buffer *bufp; +{ + re_char *buffer = bufp->buffer; + + print_partial_compiled_pattern (buffer, buffer + bufp->used); + printf ("%ld bytes used/%ld bytes allocated.\n", + bufp->used, bufp->allocated); + + if (bufp->fastmap_accurate && bufp->fastmap) + { + printf ("fastmap: "); + print_fastmap (bufp->fastmap); + } + + printf ("re_nsub: %d\t", bufp->re_nsub); + printf ("regs_alloc: %d\t", bufp->regs_allocated); + printf ("can_be_null: %d\t", bufp->can_be_null); + printf ("no_sub: %d\t", bufp->no_sub); + printf ("not_bol: %d\t", bufp->not_bol); + printf ("not_eol: %d\t", bufp->not_eol); + printf ("syntax: %lx\n", bufp->syntax); + fflush (stdout); + /* Perhaps we should print the translate table? */ +} + + +void +print_double_string (where, string1, size1, string2, size2) + re_char *where; + re_char *string1; + re_char *string2; + int size1; + int size2; +{ + int this_char; + + if (where == NULL) + printf ("(null)"); + else + { + if (FIRST_STRING_P (where)) + { + for (this_char = where - string1; this_char < size1; this_char++) + putchar (string1[this_char]); + + where = string2; + } + + for (this_char = where - string2; this_char < size2; this_char++) + putchar (string2[this_char]); + } +} + +#else /* not DEBUG */ + +# undef assert +# define assert(e) + +# define DEBUG_STATEMENT(e) +# define DEBUG_PRINT1(x) +# define DEBUG_PRINT2(x1, x2) +# define DEBUG_PRINT3(x1, x2, x3) +# define DEBUG_PRINT4(x1, x2, x3, x4) +# define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) +# define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2) + +#endif /* not DEBUG */ + +/* Set by `re_set_syntax' to the current regexp syntax to recognize. Can + also be assigned to arbitrarily: each pattern buffer stores its own + syntax, so it can be changed between regex compilations. */ +/* This has no initializer because initialized variables in Emacs + become read-only after dumping. */ +reg_syntax_t re_syntax_options; + + +/* Specify the precise syntax of regexps for compilation. This provides + for compatibility for various utilities which historically have + different, incompatible syntaxes. + + The argument SYNTAX is a bit mask comprised of the various bits + defined in regex.h. We return the old syntax. */ + +reg_syntax_t +re_set_syntax (syntax) + reg_syntax_t syntax; +{ + reg_syntax_t ret = re_syntax_options; + + re_syntax_options = syntax; + return ret; +} +WEAK_ALIAS (__re_set_syntax, re_set_syntax) + +/* This table gives an error message for each of the error codes listed + in regex.h. Obviously the order here has to be same as there. + POSIX doesn't require that we do anything for REG_NOERROR, + but why not be nice? */ + +static const char *re_error_msgid[] = + { + gettext_noop ("Success"), /* REG_NOERROR */ + gettext_noop ("No match"), /* REG_NOMATCH */ + gettext_noop ("Invalid regular expression"), /* REG_BADPAT */ + gettext_noop ("Invalid collation character"), /* REG_ECOLLATE */ + gettext_noop ("Invalid character class name"), /* REG_ECTYPE */ + gettext_noop ("Trailing backslash"), /* REG_EESCAPE */ + gettext_noop ("Invalid back reference"), /* REG_ESUBREG */ + gettext_noop ("Unmatched [ or [^"), /* REG_EBRACK */ + gettext_noop ("Unmatched ( or \\("), /* REG_EPAREN */ + gettext_noop ("Unmatched \\{"), /* REG_EBRACE */ + gettext_noop ("Invalid content of \\{\\}"), /* REG_BADBR */ + gettext_noop ("Invalid range end"), /* REG_ERANGE */ + gettext_noop ("Memory exhausted"), /* REG_ESPACE */ + gettext_noop ("Invalid preceding regular expression"), /* REG_BADRPT */ + gettext_noop ("Premature end of regular expression"), /* REG_EEND */ + gettext_noop ("Regular expression too big"), /* REG_ESIZE */ + gettext_noop ("Unmatched ) or \\)"), /* REG_ERPAREN */ + }; + +/* Avoiding alloca during matching, to placate r_alloc. */ + +/* Define MATCH_MAY_ALLOCATE unless we need to make sure that the + searching and matching functions should not call alloca. On some + systems, alloca is implemented in terms of malloc, and if we're + using the relocating allocator routines, then malloc could cause a + relocation, which might (if the strings being searched are in the + ralloc heap) shift the data out from underneath the regexp + routines. + + Here's another reason to avoid allocation: Emacs + processes input from X in a signal handler; processing X input may + call malloc; if input arrives while a matching routine is calling + malloc, then we're scrod. But Emacs can't just block input while + calling matching routines; then we don't notice interrupts when + they come in. So, Emacs blocks input around all regexp calls + except the matching calls, which it leaves unprotected, in the + faith that they will not malloc. */ + +/* Normally, this is fine. */ +#define MATCH_MAY_ALLOCATE + +/* When using GNU C, we are not REALLY using the C alloca, no matter + what config.h may say. So don't take precautions for it. */ +#ifdef __GNUC__ +# undef C_ALLOCA +#endif + +/* The match routines may not allocate if (1) they would do it with malloc + and (2) it's not safe for them to use malloc. + Note that if REL_ALLOC is defined, matching would not use malloc for the + failure stack, but we would still use it for the register vectors; + so REL_ALLOC should not affect this. */ +#if (defined C_ALLOCA || defined REGEX_MALLOC) && defined emacs +# undef MATCH_MAY_ALLOCATE +#endif + + +/* Failure stack declarations and macros; both re_compile_fastmap and + re_match_2 use a failure stack. These have to be macros because of + REGEX_ALLOCATE_STACK. */ + + +/* Approximate number of failure points for which to initially allocate space + when matching. If this number is exceeded, we allocate more + space, so it is not a hard limit. */ +#ifndef INIT_FAILURE_ALLOC +# define INIT_FAILURE_ALLOC 20 +#endif + +/* Roughly the maximum number of failure points on the stack. Would be + exactly that if always used TYPICAL_FAILURE_SIZE items each time we failed. + This is a variable only so users of regex can assign to it; we never + change it ourselves. We always multiply it by TYPICAL_FAILURE_SIZE + before using it, so it should probably be a byte-count instead. */ +# if defined MATCH_MAY_ALLOCATE +/* Note that 4400 was enough to cause a crash on Alpha OSF/1, + whose default stack limit is 2mb. In order for a larger + value to work reliably, you have to try to make it accord + with the process stack limit. */ +size_t re_max_failures = 40000; +# else +size_t re_max_failures = 4000; +# endif + +union fail_stack_elt +{ + re_char *pointer; + /* This should be the biggest `int' that's no bigger than a pointer. */ + long integer; +}; + +typedef union fail_stack_elt fail_stack_elt_t; + +typedef struct +{ + fail_stack_elt_t *stack; + size_t size; + size_t avail; /* Offset of next open position. */ + size_t frame; /* Offset of the cur constructed frame. */ +} fail_stack_type; + +#define FAIL_STACK_EMPTY() (fail_stack.frame == 0) +#define FAIL_STACK_FULL() (fail_stack.avail == fail_stack.size) + + +/* Define macros to initialize and free the failure stack. + Do `return -2' if the alloc fails. */ + +#ifdef MATCH_MAY_ALLOCATE +# define INIT_FAIL_STACK() \ + do { \ + fail_stack.stack = (fail_stack_elt_t *) \ + REGEX_ALLOCATE_STACK (INIT_FAILURE_ALLOC * TYPICAL_FAILURE_SIZE \ + * sizeof (fail_stack_elt_t)); \ + \ + if (fail_stack.stack == NULL) \ + return -2; \ + \ + fail_stack.size = INIT_FAILURE_ALLOC; \ + fail_stack.avail = 0; \ + fail_stack.frame = 0; \ + } while (0) + +# define RESET_FAIL_STACK() REGEX_FREE_STACK (fail_stack.stack) +#else +# define INIT_FAIL_STACK() \ + do { \ + fail_stack.avail = 0; \ + fail_stack.frame = 0; \ + } while (0) + +# define RESET_FAIL_STACK() ((void)0) +#endif + + +/* Double the size of FAIL_STACK, up to a limit + which allows approximately `re_max_failures' items. + + Return 1 if succeeds, and 0 if either ran out of memory + allocating space for it or it was already too large. + + REGEX_REALLOCATE_STACK requires `destination' be declared. */ + +/* Factor to increase the failure stack size by + when we increase it. + This used to be 2, but 2 was too wasteful + because the old discarded stacks added up to as much space + were as ultimate, maximum-size stack. */ +#define FAIL_STACK_GROWTH_FACTOR 4 + +#define GROW_FAIL_STACK(fail_stack) \ + (((fail_stack).size * sizeof (fail_stack_elt_t) \ + >= re_max_failures * TYPICAL_FAILURE_SIZE) \ + ? 0 \ + : ((fail_stack).stack \ + = (fail_stack_elt_t *) \ + REGEX_REALLOCATE_STACK ((fail_stack).stack, \ + (fail_stack).size * sizeof (fail_stack_elt_t), \ + MIN (re_max_failures * TYPICAL_FAILURE_SIZE, \ + ((fail_stack).size * sizeof (fail_stack_elt_t) \ + * FAIL_STACK_GROWTH_FACTOR))), \ + \ + (fail_stack).stack == NULL \ + ? 0 \ + : ((fail_stack).size \ + = (MIN (re_max_failures * TYPICAL_FAILURE_SIZE, \ + ((fail_stack).size * sizeof (fail_stack_elt_t) \ + * FAIL_STACK_GROWTH_FACTOR)) \ + / sizeof (fail_stack_elt_t)), \ + 1))) + + +/* Push a pointer value onto the failure stack. + Assumes the variable `fail_stack'. Probably should only + be called from within `PUSH_FAILURE_POINT'. */ +#define PUSH_FAILURE_POINTER(item) \ + fail_stack.stack[fail_stack.avail++].pointer = (item) + +/* This pushes an integer-valued item onto the failure stack. + Assumes the variable `fail_stack'. Probably should only + be called from within `PUSH_FAILURE_POINT'. */ +#define PUSH_FAILURE_INT(item) \ + fail_stack.stack[fail_stack.avail++].integer = (item) + +/* Push a fail_stack_elt_t value onto the failure stack. + Assumes the variable `fail_stack'. Probably should only + be called from within `PUSH_FAILURE_POINT'. */ +#define PUSH_FAILURE_ELT(item) \ + fail_stack.stack[fail_stack.avail++] = (item) + +/* These three POP... operations complement the three PUSH... operations. + All assume that `fail_stack' is nonempty. */ +#define POP_FAILURE_POINTER() fail_stack.stack[--fail_stack.avail].pointer +#define POP_FAILURE_INT() fail_stack.stack[--fail_stack.avail].integer +#define POP_FAILURE_ELT() fail_stack.stack[--fail_stack.avail] + +/* Individual items aside from the registers. */ +#define NUM_NONREG_ITEMS 3 + +/* Used to examine the stack (to detect infinite loops). */ +#define FAILURE_PAT(h) fail_stack.stack[(h) - 1].pointer +#define FAILURE_STR(h) (fail_stack.stack[(h) - 2].pointer) +#define NEXT_FAILURE_HANDLE(h) fail_stack.stack[(h) - 3].integer +#define TOP_FAILURE_HANDLE() fail_stack.frame + + +#define ENSURE_FAIL_STACK(space) \ +while (REMAINING_AVAIL_SLOTS <= space) { \ + if (!GROW_FAIL_STACK (fail_stack)) \ + return -2; \ + DEBUG_PRINT2 ("\n Doubled stack; size now: %d\n", (fail_stack).size);\ + DEBUG_PRINT2 (" slots available: %d\n", REMAINING_AVAIL_SLOTS);\ +} + +/* Push register NUM onto the stack. */ +#define PUSH_FAILURE_REG(num) \ +do { \ + char *destination; \ + ENSURE_FAIL_STACK(3); \ + DEBUG_PRINT4 (" Push reg %d (spanning %p -> %p)\n", \ + num, regstart[num], regend[num]); \ + PUSH_FAILURE_POINTER (regstart[num]); \ + PUSH_FAILURE_POINTER (regend[num]); \ + PUSH_FAILURE_INT (num); \ +} while (0) + +/* Change the counter's value to VAL, but make sure that it will + be reset when backtracking. */ +#define PUSH_NUMBER(ptr,val) \ +do { \ + char *destination; \ + int c; \ + ENSURE_FAIL_STACK(3); \ + EXTRACT_NUMBER (c, ptr); \ + DEBUG_PRINT4 (" Push number %p = %d -> %d\n", ptr, c, val); \ + PUSH_FAILURE_INT (c); \ + PUSH_FAILURE_POINTER (ptr); \ + PUSH_FAILURE_INT (-1); \ + STORE_NUMBER (ptr, val); \ +} while (0) + +/* Pop a saved register off the stack. */ +#define POP_FAILURE_REG_OR_COUNT() \ +do { \ + int reg = POP_FAILURE_INT (); \ + if (reg == -1) \ + { \ + /* It's a counter. */ \ + /* Here, we discard `const', making re_match non-reentrant. */ \ + unsigned char *ptr = (unsigned char*) POP_FAILURE_POINTER (); \ + reg = POP_FAILURE_INT (); \ + STORE_NUMBER (ptr, reg); \ + DEBUG_PRINT3 (" Pop counter %p = %d\n", ptr, reg); \ + } \ + else \ + { \ + regend[reg] = POP_FAILURE_POINTER (); \ + regstart[reg] = POP_FAILURE_POINTER (); \ + DEBUG_PRINT4 (" Pop reg %d (spanning %p -> %p)\n", \ + reg, regstart[reg], regend[reg]); \ + } \ +} while (0) + +/* Check that we are not stuck in an infinite loop. */ +#define CHECK_INFINITE_LOOP(pat_cur, string_place) \ +do { \ + int failure = TOP_FAILURE_HANDLE (); \ + /* Check for infinite matching loops */ \ + while (failure > 0 \ + && (FAILURE_STR (failure) == string_place \ + || FAILURE_STR (failure) == NULL)) \ + { \ + assert (FAILURE_PAT (failure) >= bufp->buffer \ + && FAILURE_PAT (failure) <= bufp->buffer + bufp->used); \ + if (FAILURE_PAT (failure) == pat_cur) \ + { \ + cycle = 1; \ + break; \ + } \ + DEBUG_PRINT2 (" Other pattern: %p\n", FAILURE_PAT (failure)); \ + failure = NEXT_FAILURE_HANDLE(failure); \ + } \ + DEBUG_PRINT2 (" Other string: %p\n", FAILURE_STR (failure)); \ +} while (0) + +/* Push the information about the state we will need + if we ever fail back to it. + + Requires variables fail_stack, regstart, regend and + num_regs be declared. GROW_FAIL_STACK requires `destination' be + declared. + + Does `return FAILURE_CODE' if runs out of memory. */ + +#define PUSH_FAILURE_POINT(pattern, string_place) \ +do { \ + char *destination; \ + /* Must be int, so when we don't save any registers, the arithmetic \ + of 0 + -1 isn't done as unsigned. */ \ + \ + DEBUG_STATEMENT (nfailure_points_pushed++); \ + DEBUG_PRINT1 ("\nPUSH_FAILURE_POINT:\n"); \ + DEBUG_PRINT2 (" Before push, next avail: %d\n", (fail_stack).avail); \ + DEBUG_PRINT2 (" size: %d\n", (fail_stack).size);\ + \ + ENSURE_FAIL_STACK (NUM_NONREG_ITEMS); \ + \ + DEBUG_PRINT1 ("\n"); \ + \ + DEBUG_PRINT2 (" Push frame index: %d\n", fail_stack.frame); \ + PUSH_FAILURE_INT (fail_stack.frame); \ + \ + DEBUG_PRINT2 (" Push string %p: `", string_place); \ + DEBUG_PRINT_DOUBLE_STRING (string_place, string1, size1, string2, size2);\ + DEBUG_PRINT1 ("'\n"); \ + PUSH_FAILURE_POINTER (string_place); \ + \ + DEBUG_PRINT2 (" Push pattern %p: ", pattern); \ + DEBUG_PRINT_COMPILED_PATTERN (bufp, pattern, pend); \ + PUSH_FAILURE_POINTER (pattern); \ + \ + /* Close the frame by moving the frame pointer past it. */ \ + fail_stack.frame = fail_stack.avail; \ +} while (0) + +/* Estimate the size of data pushed by a typical failure stack entry. + An estimate is all we need, because all we use this for + is to choose a limit for how big to make the failure stack. */ +/* BEWARE, the value `20' is hard-coded in emacs.c:main(). */ +#define TYPICAL_FAILURE_SIZE 20 + +/* How many items can still be added to the stack without overflowing it. */ +#define REMAINING_AVAIL_SLOTS ((fail_stack).size - (fail_stack).avail) + + +/* Pops what PUSH_FAIL_STACK pushes. + + We restore into the parameters, all of which should be lvalues: + STR -- the saved data position. + PAT -- the saved pattern position. + REGSTART, REGEND -- arrays of string positions. + + Also assumes the variables `fail_stack' and (if debugging), `bufp', + `pend', `string1', `size1', `string2', and `size2'. */ + +#define POP_FAILURE_POINT(str, pat) \ +do { \ + assert (!FAIL_STACK_EMPTY ()); \ + \ + /* Remove failure points and point to how many regs pushed. */ \ + DEBUG_PRINT1 ("POP_FAILURE_POINT:\n"); \ + DEBUG_PRINT2 (" Before pop, next avail: %d\n", fail_stack.avail); \ + DEBUG_PRINT2 (" size: %d\n", fail_stack.size); \ + \ + /* Pop the saved registers. */ \ + while (fail_stack.frame < fail_stack.avail) \ + POP_FAILURE_REG_OR_COUNT (); \ + \ + pat = POP_FAILURE_POINTER (); \ + DEBUG_PRINT2 (" Popping pattern %p: ", pat); \ + DEBUG_PRINT_COMPILED_PATTERN (bufp, pat, pend); \ + \ + /* If the saved string location is NULL, it came from an \ + on_failure_keep_string_jump opcode, and we want to throw away the \ + saved NULL, thus retaining our current position in the string. */ \ + str = POP_FAILURE_POINTER (); \ + DEBUG_PRINT2 (" Popping string %p: `", str); \ + DEBUG_PRINT_DOUBLE_STRING (str, string1, size1, string2, size2); \ + DEBUG_PRINT1 ("'\n"); \ + \ + fail_stack.frame = POP_FAILURE_INT (); \ + DEBUG_PRINT2 (" Popping frame index: %d\n", fail_stack.frame); \ + \ + assert (fail_stack.avail >= 0); \ + assert (fail_stack.frame <= fail_stack.avail); \ + \ + DEBUG_STATEMENT (nfailure_points_popped++); \ +} while (0) /* POP_FAILURE_POINT */ + + + +/* Registers are set to a sentinel when they haven't yet matched. */ +#define REG_UNSET(e) ((e) == NULL) + +/* Subroutine declarations and macros for regex_compile. */ + +static reg_errcode_t regex_compile _RE_ARGS ((re_char *pattern, size_t size, + reg_syntax_t syntax, + struct re_pattern_buffer *bufp)); +static void store_op1 _RE_ARGS ((re_opcode_t op, unsigned char *loc, int arg)); +static void store_op2 _RE_ARGS ((re_opcode_t op, unsigned char *loc, + int arg1, int arg2)); +static void insert_op1 _RE_ARGS ((re_opcode_t op, unsigned char *loc, + int arg, unsigned char *end)); +static void insert_op2 _RE_ARGS ((re_opcode_t op, unsigned char *loc, + int arg1, int arg2, unsigned char *end)); +static boolean at_begline_loc_p _RE_ARGS ((re_char *pattern, + re_char *p, + reg_syntax_t syntax)); +static boolean at_endline_loc_p _RE_ARGS ((re_char *p, + re_char *pend, + reg_syntax_t syntax)); +static re_char *skip_one_char _RE_ARGS ((re_char *p)); +static int analyse_first _RE_ARGS ((re_char *p, re_char *pend, + char *fastmap, const int multibyte)); + +/* Fetch the next character in the uncompiled pattern, with no + translation. */ +#define PATFETCH(c) \ + do { \ + int len; \ + if (p == pend) return REG_EEND; \ + c = RE_STRING_CHAR_AND_LENGTH (p, pend - p, len); \ + p += len; \ + } while (0) + + +/* If `translate' is non-null, return translate[D], else just D. We + cast the subscript to translate because some data is declared as + `char *', to avoid warnings when a string constant is passed. But + when we use a character as a subscript we must make it unsigned. */ +#ifndef TRANSLATE +# define TRANSLATE(d) \ + (RE_TRANSLATE_P (translate) ? RE_TRANSLATE (translate, (d)) : (d)) +#endif + + +/* Macros for outputting the compiled pattern into `buffer'. */ + +/* If the buffer isn't allocated when it comes in, use this. */ +#define INIT_BUF_SIZE 32 + +/* Make sure we have at least N more bytes of space in buffer. */ +#define GET_BUFFER_SPACE(n) \ + while ((size_t) (b - bufp->buffer + (n)) > bufp->allocated) \ + EXTEND_BUFFER () + +/* Make sure we have one more byte of buffer space and then add C to it. */ +#define BUF_PUSH(c) \ + do { \ + GET_BUFFER_SPACE (1); \ + *b++ = (unsigned char) (c); \ + } while (0) + + +/* Ensure we have two more bytes of buffer space and then append C1 and C2. */ +#define BUF_PUSH_2(c1, c2) \ + do { \ + GET_BUFFER_SPACE (2); \ + *b++ = (unsigned char) (c1); \ + *b++ = (unsigned char) (c2); \ + } while (0) + + +/* As with BUF_PUSH_2, except for three bytes. */ +#define BUF_PUSH_3(c1, c2, c3) \ + do { \ + GET_BUFFER_SPACE (3); \ + *b++ = (unsigned char) (c1); \ + *b++ = (unsigned char) (c2); \ + *b++ = (unsigned char) (c3); \ + } while (0) + + +/* Store a jump with opcode OP at LOC to location TO. We store a + relative address offset by the three bytes the jump itself occupies. */ +#define STORE_JUMP(op, loc, to) \ + store_op1 (op, loc, (to) - (loc) - 3) + +/* Likewise, for a two-argument jump. */ +#define STORE_JUMP2(op, loc, to, arg) \ + store_op2 (op, loc, (to) - (loc) - 3, arg) + +/* Like `STORE_JUMP', but for inserting. Assume `b' is the buffer end. */ +#define INSERT_JUMP(op, loc, to) \ + insert_op1 (op, loc, (to) - (loc) - 3, b) + +/* Like `STORE_JUMP2', but for inserting. Assume `b' is the buffer end. */ +#define INSERT_JUMP2(op, loc, to, arg) \ + insert_op2 (op, loc, (to) - (loc) - 3, arg, b) + + +/* This is not an arbitrary limit: the arguments which represent offsets + into the pattern are two bytes long. So if 2^15 bytes turns out to + be too small, many things would have to change. */ +# define MAX_BUF_SIZE (1L << 15) + +#if 0 /* This is when we thought it could be 2^16 bytes. */ +/* Any other compiler which, like MSC, has allocation limit below 2^16 + bytes will have to use approach similar to what was done below for + MSC and drop MAX_BUF_SIZE a bit. Otherwise you may end up + reallocating to 0 bytes. Such thing is not going to work too well. + You have been warned!! */ +#if defined _MSC_VER && !defined WIN32 +/* Microsoft C 16-bit versions limit malloc to approx 65512 bytes. */ +# define MAX_BUF_SIZE 65500L +#else +# define MAX_BUF_SIZE (1L << 16) +#endif +#endif /* 0 */ + +/* Extend the buffer by twice its current size via realloc and + reset the pointers that pointed into the old block to point to the + correct places in the new one. If extending the buffer results in it + being larger than MAX_BUF_SIZE, then flag memory exhausted. */ +#if __BOUNDED_POINTERS__ +# define SET_HIGH_BOUND(P) (__ptrhigh (P) = __ptrlow (P) + bufp->allocated) +# define MOVE_BUFFER_POINTER(P) \ + (__ptrlow (P) += incr, SET_HIGH_BOUND (P), __ptrvalue (P) += incr) +# define ELSE_EXTEND_BUFFER_HIGH_BOUND \ + else \ + { \ + SET_HIGH_BOUND (b); \ + SET_HIGH_BOUND (begalt); \ + if (fixup_alt_jump) \ + SET_HIGH_BOUND (fixup_alt_jump); \ + if (laststart) \ + SET_HIGH_BOUND (laststart); \ + if (pending_exact) \ + SET_HIGH_BOUND (pending_exact); \ + } +#else +# define MOVE_BUFFER_POINTER(P) (P) += incr +# define ELSE_EXTEND_BUFFER_HIGH_BOUND +#endif +#define EXTEND_BUFFER() \ + do { \ + re_char *old_buffer = bufp->buffer; \ + if (bufp->allocated == MAX_BUF_SIZE) \ + return REG_ESIZE; \ + bufp->allocated <<= 1; \ + if (bufp->allocated > MAX_BUF_SIZE) \ + bufp->allocated = MAX_BUF_SIZE; \ + RETALLOC (bufp->buffer, bufp->allocated, unsigned char); \ + if (bufp->buffer == NULL) \ + return REG_ESPACE; \ + /* If the buffer moved, move all the pointers into it. */ \ + if (old_buffer != bufp->buffer) \ + { \ + int incr = bufp->buffer - old_buffer; \ + MOVE_BUFFER_POINTER (b); \ + MOVE_BUFFER_POINTER (begalt); \ + if (fixup_alt_jump) \ + MOVE_BUFFER_POINTER (fixup_alt_jump); \ + if (laststart) \ + MOVE_BUFFER_POINTER (laststart); \ + if (pending_exact) \ + MOVE_BUFFER_POINTER (pending_exact); \ + } \ + ELSE_EXTEND_BUFFER_HIGH_BOUND \ + } while (0) + + +/* Since we have one byte reserved for the register number argument to + {start,stop}_memory, the maximum number of groups we can report + things about is what fits in that byte. */ +#define MAX_REGNUM 255 + +/* But patterns can have more than `MAX_REGNUM' registers. We just + ignore the excess. */ +typedef int regnum_t; + + +/* Macros for the compile stack. */ + +/* Since offsets can go either forwards or backwards, this type needs to + be able to hold values from -(MAX_BUF_SIZE - 1) to MAX_BUF_SIZE - 1. */ +/* int may be not enough when sizeof(int) == 2. */ +typedef long pattern_offset_t; + +typedef struct +{ + pattern_offset_t begalt_offset; + pattern_offset_t fixup_alt_jump; + pattern_offset_t laststart_offset; + regnum_t regnum; +} compile_stack_elt_t; + + +typedef struct +{ + compile_stack_elt_t *stack; + unsigned size; + unsigned avail; /* Offset of next open position. */ +} compile_stack_type; + + +#define INIT_COMPILE_STACK_SIZE 32 + +#define COMPILE_STACK_EMPTY (compile_stack.avail == 0) +#define COMPILE_STACK_FULL (compile_stack.avail == compile_stack.size) + +/* The next available element. */ +#define COMPILE_STACK_TOP (compile_stack.stack[compile_stack.avail]) + +/* Explicit quit checking is only used on NTemacs. */ +#if defined WINDOWSNT && defined emacs && defined QUIT +extern int immediate_quit; +# define IMMEDIATE_QUIT_CHECK \ + do { \ + if (immediate_quit) QUIT; \ + } while (0) +#else +# define IMMEDIATE_QUIT_CHECK ((void)0) +#endif + +/* Structure to manage work area for range table. */ +struct range_table_work_area +{ + int *table; /* actual work area. */ + int allocated; /* allocated size for work area in bytes. */ + int used; /* actually used size in words. */ + int bits; /* flag to record character classes */ +}; + +/* Make sure that WORK_AREA can hold more N multibyte characters. + This is used only in set_image_of_range and set_image_of_range_1. + It expects WORK_AREA to be a pointer. + If it can't get the space, it returns from the surrounding function. */ + +#define EXTEND_RANGE_TABLE(work_area, n) \ + do { \ + if (((work_area)->used + (n)) * sizeof (int) > (work_area)->allocated) \ + { \ + extend_range_table_work_area (work_area); \ + if ((work_area)->table == 0) \ + return (REG_ESPACE); \ + } \ + } while (0) + +#define SET_RANGE_TABLE_WORK_AREA_BIT(work_area, bit) \ + (work_area).bits |= (bit) + +/* Bits used to implement the multibyte-part of the various character classes + such as [:alnum:] in a charset's range table. */ +#define BIT_WORD 0x1 +#define BIT_LOWER 0x2 +#define BIT_PUNCT 0x4 +#define BIT_SPACE 0x8 +#define BIT_UPPER 0x10 +#define BIT_MULTIBYTE 0x20 + +/* Set a range START..END to WORK_AREA. + The range is passed through TRANSLATE, so START and END + should be untranslated. */ +#define SET_RANGE_TABLE_WORK_AREA(work_area, start, end) \ + do { \ + int tem; \ + tem = set_image_of_range (&work_area, start, end, translate); \ + if (tem > 0) \ + FREE_STACK_RETURN (tem); \ + } while (0) + +/* Free allocated memory for WORK_AREA. */ +#define FREE_RANGE_TABLE_WORK_AREA(work_area) \ + do { \ + if ((work_area).table) \ + free ((work_area).table); \ + } while (0) + +#define CLEAR_RANGE_TABLE_WORK_USED(work_area) ((work_area).used = 0, (work_area).bits = 0) +#define RANGE_TABLE_WORK_USED(work_area) ((work_area).used) +#define RANGE_TABLE_WORK_BITS(work_area) ((work_area).bits) +#define RANGE_TABLE_WORK_ELT(work_area, i) ((work_area).table[i]) + + +/* Set the bit for character C in a list. */ +#define SET_LIST_BIT(c) (b[((c)) / BYTEWIDTH] |= 1 << ((c) % BYTEWIDTH)) + + +/* Get the next unsigned number in the uncompiled pattern. */ +#define GET_UNSIGNED_NUMBER(num) \ + do { if (p != pend) \ + { \ + PATFETCH (c); \ + if (c == ' ') \ + FREE_STACK_RETURN (REG_BADBR); \ + while ('0' <= c && c <= '9') \ + { \ + int prev; \ + if (num < 0) \ + num = 0; \ + prev = num; \ + num = num * 10 + c - '0'; \ + if (num / 10 != prev) \ + FREE_STACK_RETURN (REG_BADBR); \ + if (p == pend) \ + break; \ + PATFETCH (c); \ + } \ + if (c == ' ') \ + FREE_STACK_RETURN (REG_BADBR); \ + } \ + } while (0) + +#if WIDE_CHAR_SUPPORT +/* The GNU C library provides support for user-defined character classes + and the functions from ISO C amendement 1. */ +# ifdef CHARCLASS_NAME_MAX +# define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX +# else +/* This shouldn't happen but some implementation might still have this + problem. Use a reasonable default value. */ +# define CHAR_CLASS_MAX_LENGTH 256 +# endif +typedef wctype_t re_wctype_t; +typedef wchar_t re_wchar_t; +# define re_wctype wctype +# define re_iswctype iswctype +# define re_wctype_to_bit(cc) 0 +#else +# define CHAR_CLASS_MAX_LENGTH 9 /* Namely, `multibyte'. */ +# define btowc(c) c + +/* Character classes. */ +typedef enum { RECC_ERROR = 0, + RECC_ALNUM, RECC_ALPHA, RECC_WORD, + RECC_GRAPH, RECC_PRINT, + RECC_LOWER, RECC_UPPER, + RECC_PUNCT, RECC_CNTRL, + RECC_DIGIT, RECC_XDIGIT, + RECC_BLANK, RECC_SPACE, + RECC_MULTIBYTE, RECC_NONASCII, + RECC_ASCII, RECC_UNIBYTE +} re_wctype_t; + +typedef int re_wchar_t; + +/* Map a string to the char class it names (if any). */ +static re_wctype_t +re_wctype (str) + re_char *str; +{ + const char *string = str; + if (STREQ (string, "alnum")) return RECC_ALNUM; + else if (STREQ (string, "alpha")) return RECC_ALPHA; + else if (STREQ (string, "word")) return RECC_WORD; + else if (STREQ (string, "ascii")) return RECC_ASCII; + else if (STREQ (string, "nonascii")) return RECC_NONASCII; + else if (STREQ (string, "graph")) return RECC_GRAPH; + else if (STREQ (string, "lower")) return RECC_LOWER; + else if (STREQ (string, "print")) return RECC_PRINT; + else if (STREQ (string, "punct")) return RECC_PUNCT; + else if (STREQ (string, "space")) return RECC_SPACE; + else if (STREQ (string, "upper")) return RECC_UPPER; + else if (STREQ (string, "unibyte")) return RECC_UNIBYTE; + else if (STREQ (string, "multibyte")) return RECC_MULTIBYTE; + else if (STREQ (string, "digit")) return RECC_DIGIT; + else if (STREQ (string, "xdigit")) return RECC_XDIGIT; + else if (STREQ (string, "cntrl")) return RECC_CNTRL; + else if (STREQ (string, "blank")) return RECC_BLANK; + else return 0; +} + +/* True iff CH is in the char class CC. */ +static boolean +re_iswctype (ch, cc) + int ch; + re_wctype_t cc; +{ + switch (cc) + { + case RECC_ALNUM: return ISALNUM (ch); + case RECC_ALPHA: return ISALPHA (ch); + case RECC_BLANK: return ISBLANK (ch); + case RECC_CNTRL: return ISCNTRL (ch); + case RECC_DIGIT: return ISDIGIT (ch); + case RECC_GRAPH: return ISGRAPH (ch); + case RECC_LOWER: return ISLOWER (ch); + case RECC_PRINT: return ISPRINT (ch); + case RECC_PUNCT: return ISPUNCT (ch); + case RECC_SPACE: return ISSPACE (ch); + case RECC_UPPER: return ISUPPER (ch); + case RECC_XDIGIT: return ISXDIGIT (ch); + case RECC_ASCII: return IS_REAL_ASCII (ch); + case RECC_NONASCII: return !IS_REAL_ASCII (ch); + case RECC_UNIBYTE: return ISUNIBYTE (ch); + case RECC_MULTIBYTE: return !ISUNIBYTE (ch); + case RECC_WORD: return ISWORD (ch); + case RECC_ERROR: return false; + default: + abort(); + } +} + +/* Return a bit-pattern to use in the range-table bits to match multibyte + chars of class CC. */ +static int +re_wctype_to_bit (cc) + re_wctype_t cc; +{ + switch (cc) + { + case RECC_NONASCII: case RECC_PRINT: case RECC_GRAPH: + case RECC_MULTIBYTE: return BIT_MULTIBYTE; + case RECC_ALPHA: case RECC_ALNUM: case RECC_WORD: return BIT_WORD; + case RECC_LOWER: return BIT_LOWER; + case RECC_UPPER: return BIT_UPPER; + case RECC_PUNCT: return BIT_PUNCT; + case RECC_SPACE: return BIT_SPACE; + case RECC_ASCII: case RECC_DIGIT: case RECC_XDIGIT: case RECC_CNTRL: + case RECC_BLANK: case RECC_UNIBYTE: case RECC_ERROR: return 0; + default: + abort(); + } +} +#endif + +/* Filling in the work area of a range. */ + +/* Actually extend the space in WORK_AREA. */ + +static void +extend_range_table_work_area (work_area) + struct range_table_work_area *work_area; +{ + work_area->allocated += 16 * sizeof (int); + if (work_area->table) + work_area->table + = (int *) realloc (work_area->table, work_area->allocated); + else + work_area->table + = (int *) malloc (work_area->allocated); +} + +#ifdef emacs + +/* Carefully find the ranges of codes that are equivalent + under case conversion to the range start..end when passed through + TRANSLATE. Handle the case where non-letters can come in between + two upper-case letters (which happens in Latin-1). + Also handle the case of groups of more than 2 case-equivalent chars. + + The basic method is to look at consecutive characters and see + if they can form a run that can be handled as one. + + Returns -1 if successful, REG_ESPACE if ran out of space. */ + +static int +set_image_of_range_1 (work_area, start, end, translate) + RE_TRANSLATE_TYPE translate; + struct range_table_work_area *work_area; + re_wchar_t start, end; +{ + /* `one_case' indicates a character, or a run of characters, + each of which is an isolate (no case-equivalents). + This includes all ASCII non-letters. + + `two_case' indicates a character, or a run of characters, + each of which has two case-equivalent forms. + This includes all ASCII letters. + + `strange' indicates a character that has more than one + case-equivalent. */ + + enum case_type {one_case, two_case, strange}; + + /* Describe the run that is in progress, + which the next character can try to extend. + If run_type is strange, that means there really is no run. + If run_type is one_case, then run_start...run_end is the run. + If run_type is two_case, then the run is run_start...run_end, + and the case-equivalents end at run_eqv_end. */ + + enum case_type run_type = strange; + int run_start, run_end, run_eqv_end; + + Lisp_Object eqv_table; + + if (!RE_TRANSLATE_P (translate)) + { + EXTEND_RANGE_TABLE (work_area, 2); + work_area->table[work_area->used++] = (start); + work_area->table[work_area->used++] = (end); + return -1; + } + + eqv_table = XCHAR_TABLE (translate)->extras[2]; + + for (; start <= end; start++) + { + enum case_type this_type; + int eqv = RE_TRANSLATE (eqv_table, start); + int minchar, maxchar; + + /* Classify this character */ + if (eqv == start) + this_type = one_case; + else if (RE_TRANSLATE (eqv_table, eqv) == start) + this_type = two_case; + else + this_type = strange; + + if (start < eqv) + minchar = start, maxchar = eqv; + else + minchar = eqv, maxchar = start; + + /* Can this character extend the run in progress? */ + if (this_type == strange || this_type != run_type + || !(minchar == run_end + 1 + && (run_type == two_case + ? maxchar == run_eqv_end + 1 : 1))) + { + /* No, end the run. + Record each of its equivalent ranges. */ + if (run_type == one_case) + { + EXTEND_RANGE_TABLE (work_area, 2); + work_area->table[work_area->used++] = run_start; + work_area->table[work_area->used++] = run_end; + } + else if (run_type == two_case) + { + EXTEND_RANGE_TABLE (work_area, 4); + work_area->table[work_area->used++] = run_start; + work_area->table[work_area->used++] = run_end; + work_area->table[work_area->used++] + = RE_TRANSLATE (eqv_table, run_start); + work_area->table[work_area->used++] + = RE_TRANSLATE (eqv_table, run_end); + } + run_type = strange; + } + + if (this_type == strange) + { + /* For a strange character, add each of its equivalents, one + by one. Don't start a range. */ + do + { + EXTEND_RANGE_TABLE (work_area, 2); + work_area->table[work_area->used++] = eqv; + work_area->table[work_area->used++] = eqv; + eqv = RE_TRANSLATE (eqv_table, eqv); + } + while (eqv != start); + } + + /* Add this char to the run, or start a new run. */ + else if (run_type == strange) + { + /* Initialize a new range. */ + run_type = this_type; + run_start = start; + run_end = start; + run_eqv_end = RE_TRANSLATE (eqv_table, run_end); + } + else + { + /* Extend a running range. */ + run_end = minchar; + run_eqv_end = RE_TRANSLATE (eqv_table, run_end); + } + } + + /* If a run is still in progress at the end, finish it now + by recording its equivalent ranges. */ + if (run_type == one_case) + { + EXTEND_RANGE_TABLE (work_area, 2); + work_area->table[work_area->used++] = run_start; + work_area->table[work_area->used++] = run_end; + } + else if (run_type == two_case) + { + EXTEND_RANGE_TABLE (work_area, 4); + work_area->table[work_area->used++] = run_start; + work_area->table[work_area->used++] = run_end; + work_area->table[work_area->used++] + = RE_TRANSLATE (eqv_table, run_start); + work_area->table[work_area->used++] + = RE_TRANSLATE (eqv_table, run_end); + } + + return -1; +} + +#endif /* emacs */ + +/* Record the the image of the range start..end when passed through + TRANSLATE. This is not necessarily TRANSLATE(start)..TRANSLATE(end) + and is not even necessarily contiguous. + Normally we approximate it with the smallest contiguous range that contains + all the chars we need. However, for Latin-1 we go to extra effort + to do a better job. + + This function is not called for ASCII ranges. + + Returns -1 if successful, REG_ESPACE if ran out of space. */ + +static int +set_image_of_range (work_area, start, end, translate) + RE_TRANSLATE_TYPE translate; + struct range_table_work_area *work_area; + re_wchar_t start, end; +{ + re_wchar_t cmin, cmax; + +#ifdef emacs + /* For Latin-1 ranges, use set_image_of_range_1 + to get proper handling of ranges that include letters and nonletters. + For a range that includes the whole of Latin-1, this is not necessary. + For other character sets, we don't bother to get this right. */ + if (RE_TRANSLATE_P (translate) && start < 04400 + && !(start < 04200 && end >= 04377)) + { + int newend; + int tem; + newend = end; + if (newend > 04377) + newend = 04377; + tem = set_image_of_range_1 (work_area, start, newend, translate); + if (tem > 0) + return tem; + + start = 04400; + if (end < 04400) + return -1; + } +#endif + + EXTEND_RANGE_TABLE (work_area, 2); + work_area->table[work_area->used++] = (start); + work_area->table[work_area->used++] = (end); + + cmin = -1, cmax = -1; + + if (RE_TRANSLATE_P (translate)) + { + int ch; + + for (ch = start; ch <= end; ch++) + { + re_wchar_t c = TRANSLATE (ch); + if (! (start <= c && c <= end)) + { + if (cmin == -1) + cmin = c, cmax = c; + else + { + cmin = MIN (cmin, c); + cmax = MAX (cmax, c); + } + } + } + + if (cmin != -1) + { + EXTEND_RANGE_TABLE (work_area, 2); + work_area->table[work_area->used++] = (cmin); + work_area->table[work_area->used++] = (cmax); + } + } + + return -1; +} + +#ifndef MATCH_MAY_ALLOCATE + +/* If we cannot allocate large objects within re_match_2_internal, + we make the fail stack and register vectors global. + The fail stack, we grow to the maximum size when a regexp + is compiled. + The register vectors, we adjust in size each time we + compile a regexp, according to the number of registers it needs. */ + +static fail_stack_type fail_stack; + +/* Size with which the following vectors are currently allocated. + That is so we can make them bigger as needed, + but never make them smaller. */ +static int regs_allocated_size; + +static re_char ** regstart, ** regend; +static re_char **best_regstart, **best_regend; + +/* Make the register vectors big enough for NUM_REGS registers, + but don't make them smaller. */ + +static +regex_grow_registers (num_regs) + int num_regs; +{ + if (num_regs > regs_allocated_size) + { + RETALLOC_IF (regstart, num_regs, re_char *); + RETALLOC_IF (regend, num_regs, re_char *); + RETALLOC_IF (best_regstart, num_regs, re_char *); + RETALLOC_IF (best_regend, num_regs, re_char *); + + regs_allocated_size = num_regs; + } +} + +#endif /* not MATCH_MAY_ALLOCATE */ + +static boolean group_in_compile_stack _RE_ARGS ((compile_stack_type + compile_stack, + regnum_t regnum)); + +/* `regex_compile' compiles PATTERN (of length SIZE) according to SYNTAX. + Returns one of error codes defined in `regex.h', or zero for success. + + Assumes the `allocated' (and perhaps `buffer') and `translate' + fields are set in BUFP on entry. + + If it succeeds, results are put in BUFP (if it returns an error, the + contents of BUFP are undefined): + `buffer' is the compiled pattern; + `syntax' is set to SYNTAX; + `used' is set to the length of the compiled pattern; + `fastmap_accurate' is zero; + `re_nsub' is the number of subexpressions in PATTERN; + `not_bol' and `not_eol' are zero; + + The `fastmap' field is neither examined nor set. */ + +/* Insert the `jump' from the end of last alternative to "here". + The space for the jump has already been allocated. */ +#define FIXUP_ALT_JUMP() \ +do { \ + if (fixup_alt_jump) \ + STORE_JUMP (jump, fixup_alt_jump, b); \ +} while (0) + + +/* Return, freeing storage we allocated. */ +#define FREE_STACK_RETURN(value) \ + do { \ + FREE_RANGE_TABLE_WORK_AREA (range_table_work); \ + free (compile_stack.stack); \ + return value; \ + } while (0) + +static reg_errcode_t +regex_compile (pattern, size, syntax, bufp) + re_char *pattern; + size_t size; + reg_syntax_t syntax; + struct re_pattern_buffer *bufp; +{ + /* We fetch characters from PATTERN here. */ + register re_wchar_t c, c1; + + /* A random temporary spot in PATTERN. */ + re_char *p1; + + /* Points to the end of the buffer, where we should append. */ + register unsigned char *b; + + /* Keeps track of unclosed groups. */ + compile_stack_type compile_stack; + + /* Points to the current (ending) position in the pattern. */ +#ifdef AIX + /* `const' makes AIX compiler fail. */ + unsigned char *p = pattern; +#else + re_char *p = pattern; +#endif + re_char *pend = pattern + size; + + /* How to translate the characters in the pattern. */ + RE_TRANSLATE_TYPE translate = bufp->translate; + + /* Address of the count-byte of the most recently inserted `exactn' + command. This makes it possible to tell if a new exact-match + character can be added to that command or if the character requires + a new `exactn' command. */ + unsigned char *pending_exact = 0; + + /* Address of start of the most recently finished expression. + This tells, e.g., postfix * where to find the start of its + operand. Reset at the beginning of groups and alternatives. */ + unsigned char *laststart = 0; + + /* Address of beginning of regexp, or inside of last group. */ + unsigned char *begalt; + + /* Place in the uncompiled pattern (i.e., the {) to + which to go back if the interval is invalid. */ + re_char *beg_interval; + + /* Address of the place where a forward jump should go to the end of + the containing expression. Each alternative of an `or' -- except the + last -- ends with a forward jump of this sort. */ + unsigned char *fixup_alt_jump = 0; + + /* Counts open-groups as they are encountered. Remembered for the + matching close-group on the compile stack, so the same register + number is put in the stop_memory as the start_memory. */ + regnum_t regnum = 0; + + /* Work area for range table of charset. */ + struct range_table_work_area range_table_work; + + /* If the object matched can contain multibyte characters. */ + const boolean multibyte = RE_MULTIBYTE_P (bufp); + +#ifdef DEBUG + debug++; + DEBUG_PRINT1 ("\nCompiling pattern: "); + if (debug > 0) + { + unsigned debug_count; + + for (debug_count = 0; debug_count < size; debug_count++) + putchar (pattern[debug_count]); + putchar ('\n'); + } +#endif /* DEBUG */ + + /* Initialize the compile stack. */ + compile_stack.stack = TALLOC (INIT_COMPILE_STACK_SIZE, compile_stack_elt_t); + if (compile_stack.stack == NULL) + return REG_ESPACE; + + compile_stack.size = INIT_COMPILE_STACK_SIZE; + compile_stack.avail = 0; + + range_table_work.table = 0; + range_table_work.allocated = 0; + + /* Initialize the pattern buffer. */ + bufp->syntax = syntax; + bufp->fastmap_accurate = 0; + bufp->not_bol = bufp->not_eol = 0; + + /* Set `used' to zero, so that if we return an error, the pattern + printer (for debugging) will think there's no pattern. We reset it + at the end. */ + bufp->used = 0; + + /* Always count groups, whether or not bufp->no_sub is set. */ + bufp->re_nsub = 0; + +#if !defined emacs && !defined SYNTAX_TABLE + /* Initialize the syntax table. */ + init_syntax_once (); +#endif + + if (bufp->allocated == 0) + { + if (bufp->buffer) + { /* If zero allocated, but buffer is non-null, try to realloc + enough space. This loses if buffer's address is bogus, but + that is the user's responsibility. */ + RETALLOC (bufp->buffer, INIT_BUF_SIZE, unsigned char); + } + else + { /* Caller did not allocate a buffer. Do it for them. */ + bufp->buffer = TALLOC (INIT_BUF_SIZE, unsigned char); + } + if (!bufp->buffer) FREE_STACK_RETURN (REG_ESPACE); + + bufp->allocated = INIT_BUF_SIZE; + } + + begalt = b = bufp->buffer; + + /* Loop through the uncompiled pattern until we're at the end. */ + while (p != pend) + { + PATFETCH (c); + + switch (c) + { + case '^': + { + if ( /* If at start of pattern, it's an operator. */ + p == pattern + 1 + /* If context independent, it's an operator. */ + || syntax & RE_CONTEXT_INDEP_ANCHORS + /* Otherwise, depends on what's come before. */ + || at_begline_loc_p (pattern, p, syntax)) + BUF_PUSH ((syntax & RE_NO_NEWLINE_ANCHOR) ? begbuf : begline); + else + goto normal_char; + } + break; + + + case '$': + { + if ( /* If at end of pattern, it's an operator. */ + p == pend + /* If context independent, it's an operator. */ + || syntax & RE_CONTEXT_INDEP_ANCHORS + /* Otherwise, depends on what's next. */ + || at_endline_loc_p (p, pend, syntax)) + BUF_PUSH ((syntax & RE_NO_NEWLINE_ANCHOR) ? endbuf : endline); + else + goto normal_char; + } + break; + + + case '+': + case '?': + if ((syntax & RE_BK_PLUS_QM) + || (syntax & RE_LIMITED_OPS)) + goto normal_char; + handle_plus: + case '*': + /* If there is no previous pattern... */ + if (!laststart) + { + if (syntax & RE_CONTEXT_INVALID_OPS) + FREE_STACK_RETURN (REG_BADRPT); + else if (!(syntax & RE_CONTEXT_INDEP_OPS)) + goto normal_char; + } + + { + /* 1 means zero (many) matches is allowed. */ + boolean zero_times_ok = 0, many_times_ok = 0; + boolean greedy = 1; + + /* If there is a sequence of repetition chars, collapse it + down to just one (the right one). We can't combine + interval operators with these because of, e.g., `a{2}*', + which should only match an even number of `a's. */ + + for (;;) + { + if ((syntax & RE_FRUGAL) + && c == '?' && (zero_times_ok || many_times_ok)) + greedy = 0; + else + { + zero_times_ok |= c != '+'; + many_times_ok |= c != '?'; + } + + if (p == pend) + break; + else if (*p == '*' + || (!(syntax & RE_BK_PLUS_QM) + && (*p == '+' || *p == '?'))) + ; + else if (syntax & RE_BK_PLUS_QM && *p == '\\') + { + if (p+1 == pend) + FREE_STACK_RETURN (REG_EESCAPE); + if (p[1] == '+' || p[1] == '?') + PATFETCH (c); /* Gobble up the backslash. */ + else + break; + } + else + break; + /* If we get here, we found another repeat character. */ + PATFETCH (c); + } + + /* Star, etc. applied to an empty pattern is equivalent + to an empty pattern. */ + if (!laststart || laststart == b) + break; + + /* Now we know whether or not zero matches is allowed + and also whether or not two or more matches is allowed. */ + if (greedy) + { + if (many_times_ok) + { + boolean simple = skip_one_char (laststart) == b; + unsigned int startoffset = 0; + re_opcode_t ofj = + /* Check if the loop can match the empty string. */ + (simple || !analyse_first (laststart, b, NULL, 0)) + ? on_failure_jump : on_failure_jump_loop; + assert (skip_one_char (laststart) <= b); + + if (!zero_times_ok && simple) + { /* Since simple * loops can be made faster by using + on_failure_keep_string_jump, we turn simple P+ + into PP* if P is simple. */ + unsigned char *p1, *p2; + startoffset = b - laststart; + GET_BUFFER_SPACE (startoffset); + p1 = b; p2 = laststart; + while (p2 < p1) + *b++ = *p2++; + zero_times_ok = 1; + } + + GET_BUFFER_SPACE (6); + if (!zero_times_ok) + /* A + loop. */ + STORE_JUMP (ofj, b, b + 6); + else + /* Simple * loops can use on_failure_keep_string_jump + depending on what follows. But since we don't know + that yet, we leave the decision up to + on_failure_jump_smart. */ + INSERT_JUMP (simple ? on_failure_jump_smart : ofj, + laststart + startoffset, b + 6); + b += 3; + STORE_JUMP (jump, b, laststart + startoffset); + b += 3; + } + else + { + /* A simple ? pattern. */ + assert (zero_times_ok); + GET_BUFFER_SPACE (3); + INSERT_JUMP (on_failure_jump, laststart, b + 3); + b += 3; + } + } + else /* not greedy */ + { /* I wish the greedy and non-greedy cases could be merged. */ + + GET_BUFFER_SPACE (7); /* We might use less. */ + if (many_times_ok) + { + boolean emptyp = analyse_first (laststart, b, NULL, 0); + + /* The non-greedy multiple match looks like + a repeat..until: we only need a conditional jump + at the end of the loop. */ + if (emptyp) BUF_PUSH (no_op); + STORE_JUMP (emptyp ? on_failure_jump_nastyloop + : on_failure_jump, b, laststart); + b += 3; + if (zero_times_ok) + { + /* The repeat...until naturally matches one or more. + To also match zero times, we need to first jump to + the end of the loop (its conditional jump). */ + INSERT_JUMP (jump, laststart, b); + b += 3; + } + } + else + { + /* non-greedy a?? */ + INSERT_JUMP (jump, laststart, b + 3); + b += 3; + INSERT_JUMP (on_failure_jump, laststart, laststart + 6); + b += 3; + } + } + } + pending_exact = 0; + break; + + + case '.': + laststart = b; + BUF_PUSH (anychar); + break; + + + case '[': + { + CLEAR_RANGE_TABLE_WORK_USED (range_table_work); + + if (p == pend) FREE_STACK_RETURN (REG_EBRACK); + + /* Ensure that we have enough space to push a charset: the + opcode, the length count, and the bitset; 34 bytes in all. */ + GET_BUFFER_SPACE (34); + + laststart = b; + + /* We test `*p == '^' twice, instead of using an if + statement, so we only need one BUF_PUSH. */ + BUF_PUSH (*p == '^' ? charset_not : charset); + if (*p == '^') + p++; + + /* Remember the first position in the bracket expression. */ + p1 = p; + + /* Push the number of bytes in the bitmap. */ + BUF_PUSH ((1 << BYTEWIDTH) / BYTEWIDTH); + + /* Clear the whole map. */ + bzero (b, (1 << BYTEWIDTH) / BYTEWIDTH); + + /* charset_not matches newline according to a syntax bit. */ + if ((re_opcode_t) b[-2] == charset_not + && (syntax & RE_HAT_LISTS_NOT_NEWLINE)) + SET_LIST_BIT ('\n'); + + /* Read in characters and ranges, setting map bits. */ + for (;;) + { + boolean escaped_char = false; + const unsigned char *p2 = p; + + if (p == pend) FREE_STACK_RETURN (REG_EBRACK); + + /* Don't translate yet. The range TRANSLATE(X..Y) cannot + always be determined from TRANSLATE(X) and TRANSLATE(Y) + So the translation is done later in a loop. Example: + (let ((case-fold-search t)) (string-match "[A-_]" "A")) */ + PATFETCH (c); + + /* \ might escape characters inside [...] and [^...]. */ + if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\') + { + if (p == pend) FREE_STACK_RETURN (REG_EESCAPE); + + PATFETCH (c); + escaped_char = true; + } + else + { + /* Could be the end of the bracket expression. If it's + not (i.e., when the bracket expression is `[]' so + far), the ']' character bit gets set way below. */ + if (c == ']' && p2 != p1) + break; + } + + /* What should we do for the character which is + greater than 0x7F, but not BASE_LEADING_CODE_P? + XXX */ + + /* See if we're at the beginning of a possible character + class. */ + + if (!escaped_char && + syntax & RE_CHAR_CLASSES && c == '[' && *p == ':') + { + /* Leave room for the null. */ + unsigned char str[CHAR_CLASS_MAX_LENGTH + 1]; + const unsigned char *class_beg; + + PATFETCH (c); + c1 = 0; + class_beg = p; + + /* If pattern is `[[:'. */ + if (p == pend) FREE_STACK_RETURN (REG_EBRACK); + + for (;;) + { + PATFETCH (c); + if ((c == ':' && *p == ']') || p == pend) + break; + if (c1 < CHAR_CLASS_MAX_LENGTH) + str[c1++] = c; + else + /* This is in any case an invalid class name. */ + str[0] = '\0'; + } + str[c1] = '\0'; + + /* If isn't a word bracketed by `[:' and `:]': + undo the ending character, the letters, and + leave the leading `:' and `[' (but set bits for + them). */ + if (c == ':' && *p == ']') + { + re_wchar_t ch; + re_wctype_t cc; + + cc = re_wctype (str); + + if (cc == 0) + FREE_STACK_RETURN (REG_ECTYPE); + + /* Throw away the ] at the end of the character + class. */ + PATFETCH (c); + + if (p == pend) FREE_STACK_RETURN (REG_EBRACK); + + /* Most character classes in a multibyte match + just set a flag. Exceptions are is_blank, + is_digit, is_cntrl, and is_xdigit, since + they can only match ASCII characters. We + don't need to handle them for multibyte. + They are distinguished by a negative wctype. */ + + if (multibyte) + SET_RANGE_TABLE_WORK_AREA_BIT (range_table_work, + re_wctype_to_bit (cc)); + + for (ch = 0; ch < 1 << BYTEWIDTH; ++ch) + { + int translated = TRANSLATE (ch); + if (re_iswctype (btowc (ch), cc)) + SET_LIST_BIT (translated); + } + + /* Repeat the loop. */ + continue; + } + else + { + /* Go back to right after the "[:". */ + p = class_beg; + SET_LIST_BIT ('['); + + /* Because the `:' may starts the range, we + can't simply set bit and repeat the loop. + Instead, just set it to C and handle below. */ + c = ':'; + } + } + + if (p < pend && p[0] == '-' && p[1] != ']') + { + + /* Discard the `-'. */ + PATFETCH (c1); + + /* Fetch the character which ends the range. */ + PATFETCH (c1); + + if (SINGLE_BYTE_CHAR_P (c)) + { + if (! SINGLE_BYTE_CHAR_P (c1)) + { + /* Handle a range starting with a + character of less than 256, and ending + with a character of not less than 256. + Split that into two ranges, the low one + ending at 0377, and the high one + starting at the smallest character in + the charset of C1 and ending at C1. */ + int charset = CHAR_CHARSET (c1); + re_wchar_t c2 = MAKE_CHAR (charset, 0, 0); + + SET_RANGE_TABLE_WORK_AREA (range_table_work, + c2, c1); + c1 = 0377; + } + } + else if (!SAME_CHARSET_P (c, c1)) + FREE_STACK_RETURN (REG_ERANGE); + } + else + /* Range from C to C. */ + c1 = c; + + /* Set the range ... */ + if (SINGLE_BYTE_CHAR_P (c)) + /* ... into bitmap. */ + { + re_wchar_t this_char; + re_wchar_t range_start = c, range_end = c1; + + /* If the start is after the end, the range is empty. */ + if (range_start > range_end) + { + if (syntax & RE_NO_EMPTY_RANGES) + FREE_STACK_RETURN (REG_ERANGE); + /* Else, repeat the loop. */ + } + else + { + for (this_char = range_start; this_char <= range_end; + this_char++) + SET_LIST_BIT (TRANSLATE (this_char)); + } + } + else + /* ... into range table. */ + SET_RANGE_TABLE_WORK_AREA (range_table_work, c, c1); + } + + /* Discard any (non)matching list bytes that are all 0 at the + end of the map. Decrease the map-length byte too. */ + while ((int) b[-1] > 0 && b[b[-1] - 1] == 0) + b[-1]--; + b += b[-1]; + + /* Build real range table from work area. */ + if (RANGE_TABLE_WORK_USED (range_table_work) + || RANGE_TABLE_WORK_BITS (range_table_work)) + { + int i; + int used = RANGE_TABLE_WORK_USED (range_table_work); + + /* Allocate space for COUNT + RANGE_TABLE. Needs two + bytes for flags, two for COUNT, and three bytes for + each character. */ + GET_BUFFER_SPACE (4 + used * 3); + + /* Indicate the existence of range table. */ + laststart[1] |= 0x80; + + /* Store the character class flag bits into the range table. + If not in emacs, these flag bits are always 0. */ + *b++ = RANGE_TABLE_WORK_BITS (range_table_work) & 0xff; + *b++ = RANGE_TABLE_WORK_BITS (range_table_work) >> 8; + + STORE_NUMBER_AND_INCR (b, used / 2); + for (i = 0; i < used; i++) + STORE_CHARACTER_AND_INCR + (b, RANGE_TABLE_WORK_ELT (range_table_work, i)); + } + } + break; + + + case '(': + if (syntax & RE_NO_BK_PARENS) + goto handle_open; + else + goto normal_char; + + + case ')': + if (syntax & RE_NO_BK_PARENS) + goto handle_close; + else + goto normal_char; + + + case '\n': + if (syntax & RE_NEWLINE_ALT) + goto handle_alt; + else + goto normal_char; + + + case '|': + if (syntax & RE_NO_BK_VBAR) + goto handle_alt; + else + goto normal_char; + + + case '{': + if (syntax & RE_INTERVALS && syntax & RE_NO_BK_BRACES) + goto handle_interval; + else + goto normal_char; + + + case '\\': + if (p == pend) FREE_STACK_RETURN (REG_EESCAPE); + + /* Do not translate the character after the \, so that we can + distinguish, e.g., \B from \b, even if we normally would + translate, e.g., B to b. */ + PATFETCH (c); + + switch (c) + { + case '(': + if (syntax & RE_NO_BK_PARENS) + goto normal_backslash; + + handle_open: + { + int shy = 0; + if (p+1 < pend) + { + /* Look for a special (?...) construct */ + if ((syntax & RE_SHY_GROUPS) && *p == '?') + { + PATFETCH (c); /* Gobble up the '?'. */ + PATFETCH (c); + switch (c) + { + case ':': shy = 1; break; + default: + /* Only (?:...) is supported right now. */ + FREE_STACK_RETURN (REG_BADPAT); + } + } + } + + if (!shy) + { + bufp->re_nsub++; + regnum++; + } + + if (COMPILE_STACK_FULL) + { + RETALLOC (compile_stack.stack, compile_stack.size << 1, + compile_stack_elt_t); + if (compile_stack.stack == NULL) return REG_ESPACE; + + compile_stack.size <<= 1; + } + + /* These are the values to restore when we hit end of this + group. They are all relative offsets, so that if the + whole pattern moves because of realloc, they will still + be valid. */ + COMPILE_STACK_TOP.begalt_offset = begalt - bufp->buffer; + COMPILE_STACK_TOP.fixup_alt_jump + = fixup_alt_jump ? fixup_alt_jump - bufp->buffer + 1 : 0; + COMPILE_STACK_TOP.laststart_offset = b - bufp->buffer; + COMPILE_STACK_TOP.regnum = shy ? -regnum : regnum; + + /* Do not push a + start_memory for groups beyond the last one we can + represent in the compiled pattern. */ + if (regnum <= MAX_REGNUM && !shy) + BUF_PUSH_2 (start_memory, regnum); + + compile_stack.avail++; + + fixup_alt_jump = 0; + laststart = 0; + begalt = b; + /* If we've reached MAX_REGNUM groups, then this open + won't actually generate any code, so we'll have to + clear pending_exact explicitly. */ + pending_exact = 0; + break; + } + + case ')': + if (syntax & RE_NO_BK_PARENS) goto normal_backslash; + + if (COMPILE_STACK_EMPTY) + { + if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) + goto normal_backslash; + else + FREE_STACK_RETURN (REG_ERPAREN); + } + + handle_close: + FIXUP_ALT_JUMP (); + + /* See similar code for backslashed left paren above. */ + if (COMPILE_STACK_EMPTY) + { + if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) + goto normal_char; + else + FREE_STACK_RETURN (REG_ERPAREN); + } + + /* Since we just checked for an empty stack above, this + ``can't happen''. */ + assert (compile_stack.avail != 0); + { + /* We don't just want to restore into `regnum', because + later groups should continue to be numbered higher, + as in `(ab)c(de)' -- the second group is #2. */ + regnum_t this_group_regnum; + + compile_stack.avail--; + begalt = bufp->buffer + COMPILE_STACK_TOP.begalt_offset; + fixup_alt_jump + = COMPILE_STACK_TOP.fixup_alt_jump + ? bufp->buffer + COMPILE_STACK_TOP.fixup_alt_jump - 1 + : 0; + laststart = bufp->buffer + COMPILE_STACK_TOP.laststart_offset; + this_group_regnum = COMPILE_STACK_TOP.regnum; + /* If we've reached MAX_REGNUM groups, then this open + won't actually generate any code, so we'll have to + clear pending_exact explicitly. */ + pending_exact = 0; + + /* We're at the end of the group, so now we know how many + groups were inside this one. */ + if (this_group_regnum <= MAX_REGNUM && this_group_regnum > 0) + BUF_PUSH_2 (stop_memory, this_group_regnum); + } + break; + + + case '|': /* `\|'. */ + if (syntax & RE_LIMITED_OPS || syntax & RE_NO_BK_VBAR) + goto normal_backslash; + handle_alt: + if (syntax & RE_LIMITED_OPS) + goto normal_char; + + /* Insert before the previous alternative a jump which + jumps to this alternative if the former fails. */ + GET_BUFFER_SPACE (3); + INSERT_JUMP (on_failure_jump, begalt, b + 6); + pending_exact = 0; + b += 3; + + /* The alternative before this one has a jump after it + which gets executed if it gets matched. Adjust that + jump so it will jump to this alternative's analogous + jump (put in below, which in turn will jump to the next + (if any) alternative's such jump, etc.). The last such + jump jumps to the correct final destination. A picture: + _____ _____ + | | | | + | v | v + a | b | c + + If we are at `b', then fixup_alt_jump right now points to a + three-byte space after `a'. We'll put in the jump, set + fixup_alt_jump to right after `b', and leave behind three + bytes which we'll fill in when we get to after `c'. */ + + FIXUP_ALT_JUMP (); + + /* Mark and leave space for a jump after this alternative, + to be filled in later either by next alternative or + when know we're at the end of a series of alternatives. */ + fixup_alt_jump = b; + GET_BUFFER_SPACE (3); + b += 3; + + laststart = 0; + begalt = b; + break; + + + case '{': + /* If \{ is a literal. */ + if (!(syntax & RE_INTERVALS) + /* If we're at `\{' and it's not the open-interval + operator. */ + || (syntax & RE_NO_BK_BRACES)) + goto normal_backslash; + + handle_interval: + { + /* If got here, then the syntax allows intervals. */ + + /* At least (most) this many matches must be made. */ + int lower_bound = 0, upper_bound = -1; + + beg_interval = p; + + if (p == pend) + FREE_STACK_RETURN (REG_EBRACE); + + GET_UNSIGNED_NUMBER (lower_bound); + + if (c == ',') + GET_UNSIGNED_NUMBER (upper_bound); + else + /* Interval such as `{1}' => match exactly once. */ + upper_bound = lower_bound; + + if (lower_bound < 0 || upper_bound > RE_DUP_MAX + || (upper_bound >= 0 && lower_bound > upper_bound)) + FREE_STACK_RETURN (REG_BADBR); + + if (!(syntax & RE_NO_BK_BRACES)) + { + if (c != '\\') + FREE_STACK_RETURN (REG_BADBR); + + PATFETCH (c); + } + + if (c != '}') + FREE_STACK_RETURN (REG_BADBR); + + /* We just parsed a valid interval. */ + + /* If it's invalid to have no preceding re. */ + if (!laststart) + { + if (syntax & RE_CONTEXT_INVALID_OPS) + FREE_STACK_RETURN (REG_BADRPT); + else if (syntax & RE_CONTEXT_INDEP_OPS) + laststart = b; + else + goto unfetch_interval; + } + + if (upper_bound == 0) + /* If the upper bound is zero, just drop the sub pattern + altogether. */ + b = laststart; + else if (lower_bound == 1 && upper_bound == 1) + /* Just match it once: nothing to do here. */ + ; + + /* Otherwise, we have a nontrivial interval. When + we're all done, the pattern will look like: + set_number_at <jump count> <upper bound> + set_number_at <succeed_n count> <lower bound> + succeed_n <after jump addr> <succeed_n count> + <body of loop> + jump_n <succeed_n addr> <jump count> + (The upper bound and `jump_n' are omitted if + `upper_bound' is 1, though.) */ + else + { /* If the upper bound is > 1, we need to insert + more at the end of the loop. */ + unsigned int nbytes = (upper_bound < 0 ? 3 + : upper_bound > 1 ? 5 : 0); + unsigned int startoffset = 0; + + GET_BUFFER_SPACE (20); /* We might use less. */ + + if (lower_bound == 0) + { + /* A succeed_n that starts with 0 is really a + a simple on_failure_jump_loop. */ + INSERT_JUMP (on_failure_jump_loop, laststart, + b + 3 + nbytes); + b += 3; + } + else + { + /* Initialize lower bound of the `succeed_n', even + though it will be set during matching by its + attendant `set_number_at' (inserted next), + because `re_compile_fastmap' needs to know. + Jump to the `jump_n' we might insert below. */ + INSERT_JUMP2 (succeed_n, laststart, + b + 5 + nbytes, + lower_bound); + b += 5; + + /* Code to initialize the lower bound. Insert + before the `succeed_n'. The `5' is the last two + bytes of this `set_number_at', plus 3 bytes of + the following `succeed_n'. */ + insert_op2 (set_number_at, laststart, 5, lower_bound, b); + b += 5; + startoffset += 5; + } + + if (upper_bound < 0) + { + /* A negative upper bound stands for infinity, + in which case it degenerates to a plain jump. */ + STORE_JUMP (jump, b, laststart + startoffset); + b += 3; + } + else if (upper_bound > 1) + { /* More than one repetition is allowed, so + append a backward jump to the `succeed_n' + that starts this interval. + + When we've reached this during matching, + we'll have matched the interval once, so + jump back only `upper_bound - 1' times. */ + STORE_JUMP2 (jump_n, b, laststart + startoffset, + upper_bound - 1); + b += 5; + + /* The location we want to set is the second + parameter of the `jump_n'; that is `b-2' as + an absolute address. `laststart' will be + the `set_number_at' we're about to insert; + `laststart+3' the number to set, the source + for the relative address. But we are + inserting into the middle of the pattern -- + so everything is getting moved up by 5. + Conclusion: (b - 2) - (laststart + 3) + 5, + i.e., b - laststart. + + We insert this at the beginning of the loop + so that if we fail during matching, we'll + reinitialize the bounds. */ + insert_op2 (set_number_at, laststart, b - laststart, + upper_bound - 1, b); + b += 5; + } + } + pending_exact = 0; + beg_interval = NULL; + } + break; + + unfetch_interval: + /* If an invalid interval, match the characters as literals. */ + assert (beg_interval); + p = beg_interval; + beg_interval = NULL; + + /* normal_char and normal_backslash need `c'. */ + c = '{'; + + if (!(syntax & RE_NO_BK_BRACES)) + { + assert (p > pattern && p[-1] == '\\'); + goto normal_backslash; + } + else + goto normal_char; + +#ifdef emacs + /* There is no way to specify the before_dot and after_dot + operators. rms says this is ok. --karl */ + case '=': + BUF_PUSH (at_dot); + break; + + case 's': + laststart = b; + PATFETCH (c); + BUF_PUSH_2 (syntaxspec, syntax_spec_code[c]); + break; + + case 'S': + laststart = b; + PATFETCH (c); + BUF_PUSH_2 (notsyntaxspec, syntax_spec_code[c]); + break; + + case 'c': + laststart = b; + PATFETCH (c); + BUF_PUSH_2 (categoryspec, c); + break; + + case 'C': + laststart = b; + PATFETCH (c); + BUF_PUSH_2 (notcategoryspec, c); + break; +#endif /* emacs */ + + + case 'w': + if (syntax & RE_NO_GNU_OPS) + goto normal_char; + laststart = b; + BUF_PUSH_2 (syntaxspec, Sword); + break; + + + case 'W': + if (syntax & RE_NO_GNU_OPS) + goto normal_char; + laststart = b; + BUF_PUSH_2 (notsyntaxspec, Sword); + break; + + + case '<': + if (syntax & RE_NO_GNU_OPS) + goto normal_char; + BUF_PUSH (wordbeg); + break; + + case '>': + if (syntax & RE_NO_GNU_OPS) + goto normal_char; + BUF_PUSH (wordend); + break; + + case 'b': + if (syntax & RE_NO_GNU_OPS) + goto normal_char; + BUF_PUSH (wordbound); + break; + + case 'B': + if (syntax & RE_NO_GNU_OPS) + goto normal_char; + BUF_PUSH (notwordbound); + break; + + case '`': + if (syntax & RE_NO_GNU_OPS) + goto normal_char; + BUF_PUSH (begbuf); + break; + + case '\'': + if (syntax & RE_NO_GNU_OPS) + goto normal_char; + BUF_PUSH (endbuf); + break; + + case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': + { + regnum_t reg; + + if (syntax & RE_NO_BK_REFS) + goto normal_backslash; + + reg = c - '0'; + + /* Can't back reference to a subexpression before its end. */ + if (reg > regnum || group_in_compile_stack (compile_stack, reg)) + FREE_STACK_RETURN (REG_ESUBREG); + + laststart = b; + BUF_PUSH_2 (duplicate, reg); + } + break; + + + case '+': + case '?': + if (syntax & RE_BK_PLUS_QM) + goto handle_plus; + else + goto normal_backslash; + + default: + normal_backslash: + /* You might think it would be useful for \ to mean + not to translate; but if we don't translate it + it will never match anything. */ + goto normal_char; + } + break; + + + default: + /* Expects the character in `c'. */ + normal_char: + /* If no exactn currently being built. */ + if (!pending_exact + + /* If last exactn not at current position. */ + || pending_exact + *pending_exact + 1 != b + + /* We have only one byte following the exactn for the count. */ + || *pending_exact >= (1 << BYTEWIDTH) - MAX_MULTIBYTE_LENGTH + + /* If followed by a repetition operator. */ + || (p != pend && (*p == '*' || *p == '^')) + || ((syntax & RE_BK_PLUS_QM) + ? p + 1 < pend && *p == '\\' && (p[1] == '+' || p[1] == '?') + : p != pend && (*p == '+' || *p == '?')) + || ((syntax & RE_INTERVALS) + && ((syntax & RE_NO_BK_BRACES) + ? p != pend && *p == '{' + : p + 1 < pend && p[0] == '\\' && p[1] == '{'))) + { + /* Start building a new exactn. */ + + laststart = b; + + BUF_PUSH_2 (exactn, 0); + pending_exact = b - 1; + } + + GET_BUFFER_SPACE (MAX_MULTIBYTE_LENGTH); + { + int len; + + c = TRANSLATE (c); + if (multibyte) + len = CHAR_STRING (c, b); + else + *b = c, len = 1; + b += len; + (*pending_exact) += len; + } + + break; + } /* switch (c) */ + } /* while p != pend */ + + + /* Through the pattern now. */ + + FIXUP_ALT_JUMP (); + + if (!COMPILE_STACK_EMPTY) + FREE_STACK_RETURN (REG_EPAREN); + + /* If we don't want backtracking, force success + the first time we reach the end of the compiled pattern. */ + if (syntax & RE_NO_POSIX_BACKTRACKING) + BUF_PUSH (succeed); + + /* We have succeeded; set the length of the buffer. */ + bufp->used = b - bufp->buffer; + +#ifdef DEBUG + if (debug > 0) + { + re_compile_fastmap (bufp); + DEBUG_PRINT1 ("\nCompiled pattern: \n"); + print_compiled_pattern (bufp); + } + debug--; +#endif /* DEBUG */ + +#ifndef MATCH_MAY_ALLOCATE + /* Initialize the failure stack to the largest possible stack. This + isn't necessary unless we're trying to avoid calling alloca in + the search and match routines. */ + { + int num_regs = bufp->re_nsub + 1; + + if (fail_stack.size < re_max_failures * TYPICAL_FAILURE_SIZE) + { + fail_stack.size = re_max_failures * TYPICAL_FAILURE_SIZE; + + if (! fail_stack.stack) + fail_stack.stack + = (fail_stack_elt_t *) malloc (fail_stack.size + * sizeof (fail_stack_elt_t)); + else + fail_stack.stack + = (fail_stack_elt_t *) realloc (fail_stack.stack, + (fail_stack.size + * sizeof (fail_stack_elt_t))); + } + + regex_grow_registers (num_regs); + } +#endif /* not MATCH_MAY_ALLOCATE */ + + FREE_STACK_RETURN (REG_NOERROR); +} /* regex_compile */ + +/* Subroutines for `regex_compile'. */ + +/* Store OP at LOC followed by two-byte integer parameter ARG. */ + +static void +store_op1 (op, loc, arg) + re_opcode_t op; + unsigned char *loc; + int arg; +{ + *loc = (unsigned char) op; + STORE_NUMBER (loc + 1, arg); +} + + +/* Like `store_op1', but for two two-byte parameters ARG1 and ARG2. */ + +static void +store_op2 (op, loc, arg1, arg2) + re_opcode_t op; + unsigned char *loc; + int arg1, arg2; +{ + *loc = (unsigned char) op; + STORE_NUMBER (loc + 1, arg1); + STORE_NUMBER (loc + 3, arg2); +} + + +/* Copy the bytes from LOC to END to open up three bytes of space at LOC + for OP followed by two-byte integer parameter ARG. */ + +static void +insert_op1 (op, loc, arg, end) + re_opcode_t op; + unsigned char *loc; + int arg; + unsigned char *end; +{ + register unsigned char *pfrom = end; + register unsigned char *pto = end + 3; + + while (pfrom != loc) + *--pto = *--pfrom; + + store_op1 (op, loc, arg); +} + + +/* Like `insert_op1', but for two two-byte parameters ARG1 and ARG2. */ + +static void +insert_op2 (op, loc, arg1, arg2, end) + re_opcode_t op; + unsigned char *loc; + int arg1, arg2; + unsigned char *end; +{ + register unsigned char *pfrom = end; + register unsigned char *pto = end + 5; + + while (pfrom != loc) + *--pto = *--pfrom; + + store_op2 (op, loc, arg1, arg2); +} + + +/* P points to just after a ^ in PATTERN. Return true if that ^ comes + after an alternative or a begin-subexpression. We assume there is at + least one character before the ^. */ + +static boolean +at_begline_loc_p (pattern, p, syntax) + re_char *pattern, *p; + reg_syntax_t syntax; +{ + re_char *prev = p - 2; + boolean prev_prev_backslash = prev > pattern && prev[-1] == '\\'; + + return + /* After a subexpression? */ + (*prev == '(' && (syntax & RE_NO_BK_PARENS || prev_prev_backslash)) + /* After an alternative? */ + || (*prev == '|' && (syntax & RE_NO_BK_VBAR || prev_prev_backslash)) + /* After a shy subexpression? */ + || ((syntax & RE_SHY_GROUPS) && prev - 2 >= pattern + && prev[-1] == '?' && prev[-2] == '(' + && (syntax & RE_NO_BK_PARENS + || (prev - 3 >= pattern && prev[-3] == '\\'))); +} + + +/* The dual of at_begline_loc_p. This one is for $. We assume there is + at least one character after the $, i.e., `P < PEND'. */ + +static boolean +at_endline_loc_p (p, pend, syntax) + re_char *p, *pend; + reg_syntax_t syntax; +{ + re_char *next = p; + boolean next_backslash = *next == '\\'; + re_char *next_next = p + 1 < pend ? p + 1 : 0; + + return + /* Before a subexpression? */ + (syntax & RE_NO_BK_PARENS ? *next == ')' + : next_backslash && next_next && *next_next == ')') + /* Before an alternative? */ + || (syntax & RE_NO_BK_VBAR ? *next == '|' + : next_backslash && next_next && *next_next == '|'); +} + + +/* Returns true if REGNUM is in one of COMPILE_STACK's elements and + false if it's not. */ + +static boolean +group_in_compile_stack (compile_stack, regnum) + compile_stack_type compile_stack; + regnum_t regnum; +{ + int this_element; + + for (this_element = compile_stack.avail - 1; + this_element >= 0; + this_element--) + if (compile_stack.stack[this_element].regnum == regnum) + return true; + + return false; +} + +/* analyse_first. + If fastmap is non-NULL, go through the pattern and fill fastmap + with all the possible leading chars. If fastmap is NULL, don't + bother filling it up (obviously) and only return whether the + pattern could potentially match the empty string. + + Return 1 if p..pend might match the empty string. + Return 0 if p..pend matches at least one char. + Return -1 if fastmap was not updated accurately. */ + +static int +analyse_first (p, pend, fastmap, multibyte) + re_char *p, *pend; + char *fastmap; + const int multibyte; +{ + int j, k; + boolean not; + + /* If all elements for base leading-codes in fastmap is set, this + flag is set true. */ + boolean match_any_multibyte_characters = false; + + assert (p); + + /* The loop below works as follows: + - It has a working-list kept in the PATTERN_STACK and which basically + starts by only containing a pointer to the first operation. + - If the opcode we're looking at is a match against some set of + chars, then we add those chars to the fastmap and go on to the + next work element from the worklist (done via `break'). + - If the opcode is a control operator on the other hand, we either + ignore it (if it's meaningless at this point, such as `start_memory') + or execute it (if it's a jump). If the jump has several destinations + (i.e. `on_failure_jump'), then we push the other destination onto the + worklist. + We guarantee termination by ignoring backward jumps (more or less), + so that `p' is monotonically increasing. More to the point, we + never set `p' (or push) anything `<= p1'. */ + + while (p < pend) + { + /* `p1' is used as a marker of how far back a `on_failure_jump' + can go without being ignored. It is normally equal to `p' + (which prevents any backward `on_failure_jump') except right + after a plain `jump', to allow patterns such as: + 0: jump 10 + 3..9: <body> + 10: on_failure_jump 3 + as used for the *? operator. */ + re_char *p1 = p; + + switch (SWITCH_ENUM_CAST ((re_opcode_t) *p++)) + { + case succeed: + return 1; + continue; + + case duplicate: + /* If the first character has to match a backreference, that means + that the group was empty (since it already matched). Since this + is the only case that interests us here, we can assume that the + backreference must match the empty string. */ + p++; + continue; + + + /* Following are the cases which match a character. These end + with `break'. */ + + case exactn: + if (fastmap) + { + int c = RE_STRING_CHAR (p + 1, pend - p); + + if (SINGLE_BYTE_CHAR_P (c)) + fastmap[c] = 1; + else + fastmap[p[1]] = 1; + } + break; + + + case anychar: + /* We could put all the chars except for \n (and maybe \0) + but we don't bother since it is generally not worth it. */ + if (!fastmap) break; + return -1; + + + case charset_not: + /* Chars beyond end of bitmap are possible matches. + All the single-byte codes can occur in multibyte buffers. + So any that are not listed in the charset + are possible matches, even in multibyte buffers. */ + if (!fastmap) break; + for (j = CHARSET_BITMAP_SIZE (&p[-1]) * BYTEWIDTH; + j < (1 << BYTEWIDTH); j++) + fastmap[j] = 1; + /* Fallthrough */ + case charset: + if (!fastmap) break; + not = (re_opcode_t) *(p - 1) == charset_not; + for (j = CHARSET_BITMAP_SIZE (&p[-1]) * BYTEWIDTH - 1, p++; + j >= 0; j--) + if (!!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))) ^ not) + fastmap[j] = 1; + + if ((not && multibyte) + /* Any character set can possibly contain a character + which doesn't match the specified set of characters. */ + || (CHARSET_RANGE_TABLE_EXISTS_P (&p[-2]) + && CHARSET_RANGE_TABLE_BITS (&p[-2]) != 0)) + /* If we can match a character class, we can match + any character set. */ + { + set_fastmap_for_multibyte_characters: + if (match_any_multibyte_characters == false) + { + for (j = 0x80; j < 0xA0; j++) /* XXX */ + if (BASE_LEADING_CODE_P (j)) + fastmap[j] = 1; + match_any_multibyte_characters = true; + } + } + + else if (!not && CHARSET_RANGE_TABLE_EXISTS_P (&p[-2]) + && match_any_multibyte_characters == false) + { + /* Set fastmap[I] 1 where I is a base leading code of each + multibyte character in the range table. */ + int c, count; + + /* Make P points the range table. `+ 2' is to skip flag + bits for a character class. */ + p += CHARSET_BITMAP_SIZE (&p[-2]) + 2; + + /* Extract the number of ranges in range table into COUNT. */ + EXTRACT_NUMBER_AND_INCR (count, p); + for (; count > 0; count--, p += 2 * 3) /* XXX */ + { + /* Extract the start of each range. */ + EXTRACT_CHARACTER (c, p); + j = CHAR_CHARSET (c); + fastmap[CHARSET_LEADING_CODE_BASE (j)] = 1; + } + } + break; + + case syntaxspec: + case notsyntaxspec: + if (!fastmap) break; +#ifndef emacs + not = (re_opcode_t)p[-1] == notsyntaxspec; + k = *p++; + for (j = 0; j < (1 << BYTEWIDTH); j++) + if ((SYNTAX (j) == (enum syntaxcode) k) ^ not) + fastmap[j] = 1; + break; +#else /* emacs */ + /* This match depends on text properties. These end with + aborting optimizations. */ + return -1; + + case categoryspec: + case notcategoryspec: + if (!fastmap) break; + not = (re_opcode_t)p[-1] == notcategoryspec; + k = *p++; + for (j = 0; j < (1 << BYTEWIDTH); j++) + if ((CHAR_HAS_CATEGORY (j, k)) ^ not) + fastmap[j] = 1; + + if (multibyte) + /* Any character set can possibly contain a character + whose category is K (or not). */ + goto set_fastmap_for_multibyte_characters; + break; + + /* All cases after this match the empty string. These end with + `continue'. */ + + case before_dot: + case at_dot: + case after_dot: +#endif /* !emacs */ + case no_op: + case begline: + case endline: + case begbuf: + case endbuf: + case wordbound: + case notwordbound: + case wordbeg: + case wordend: + continue; + + + case jump: + EXTRACT_NUMBER_AND_INCR (j, p); + if (j < 0) + /* Backward jumps can only go back to code that we've already + visited. `re_compile' should make sure this is true. */ + break; + p += j; + switch (SWITCH_ENUM_CAST ((re_opcode_t) *p)) + { + case on_failure_jump: + case on_failure_keep_string_jump: + case on_failure_jump_loop: + case on_failure_jump_nastyloop: + case on_failure_jump_smart: + p++; + break; + default: + continue; + }; + /* Keep `p1' to allow the `on_failure_jump' we are jumping to + to jump back to "just after here". */ + /* Fallthrough */ + + case on_failure_jump: + case on_failure_keep_string_jump: + case on_failure_jump_nastyloop: + case on_failure_jump_loop: + case on_failure_jump_smart: + EXTRACT_NUMBER_AND_INCR (j, p); + if (p + j <= p1) + ; /* Backward jump to be ignored. */ + else + { /* We have to look down both arms. + We first go down the "straight" path so as to minimize + stack usage when going through alternatives. */ + int r = analyse_first (p, pend, fastmap, multibyte); + if (r) return r; + p += j; + } + continue; + + + case jump_n: + /* This code simply does not properly handle forward jump_n. */ + DEBUG_STATEMENT (EXTRACT_NUMBER (j, p); assert (j < 0)); + p += 4; + /* jump_n can either jump or fall through. The (backward) jump + case has already been handled, so we only need to look at the + fallthrough case. */ + continue; + + case succeed_n: + /* If N == 0, it should be an on_failure_jump_loop instead. */ + DEBUG_STATEMENT (EXTRACT_NUMBER (j, p + 2); assert (j > 0)); + p += 4; + /* We only care about one iteration of the loop, so we don't + need to consider the case where this behaves like an + on_failure_jump. */ + continue; + + + case set_number_at: + p += 4; + continue; + + + case start_memory: + case stop_memory: + p += 1; + continue; + + + default: + abort (); /* We have listed all the cases. */ + } /* switch *p++ */ + + /* Getting here means we have found the possible starting + characters for one path of the pattern -- and that the empty + string does not match. We need not follow this path further. */ + return 0; + } /* while p */ + + /* We reached the end without matching anything. */ + return 1; + +} /* analyse_first */ + +/* re_compile_fastmap computes a ``fastmap'' for the compiled pattern in + BUFP. A fastmap records which of the (1 << BYTEWIDTH) possible + characters can start a string that matches the pattern. This fastmap + is used by re_search to skip quickly over impossible starting points. + + Character codes above (1 << BYTEWIDTH) are not represented in the + fastmap, but the leading codes are represented. Thus, the fastmap + indicates which character sets could start a match. + + The caller must supply the address of a (1 << BYTEWIDTH)-byte data + area as BUFP->fastmap. + + We set the `fastmap', `fastmap_accurate', and `can_be_null' fields in + the pattern buffer. + + Returns 0 if we succeed, -2 if an internal error. */ + +int +re_compile_fastmap (bufp) + struct re_pattern_buffer *bufp; +{ + char *fastmap = bufp->fastmap; + int analysis; + + assert (fastmap && bufp->buffer); + + bzero (fastmap, 1 << BYTEWIDTH); /* Assume nothing's valid. */ + bufp->fastmap_accurate = 1; /* It will be when we're done. */ + + analysis = analyse_first (bufp->buffer, bufp->buffer + bufp->used, + fastmap, RE_MULTIBYTE_P (bufp)); + bufp->can_be_null = (analysis != 0); + return 0; +} /* re_compile_fastmap */ + +/* Set REGS to hold NUM_REGS registers, storing them in STARTS and + ENDS. Subsequent matches using PATTERN_BUFFER and REGS will use + this memory for recording register information. STARTS and ENDS + must be allocated using the malloc library routine, and must each + be at least NUM_REGS * sizeof (regoff_t) bytes long. + + If NUM_REGS == 0, then subsequent matches should allocate their own + register data. + + Unless this function is called, the first search or match using + PATTERN_BUFFER will allocate its own register data, without + freeing the old data. */ + +void +re_set_registers (bufp, regs, num_regs, starts, ends) + struct re_pattern_buffer *bufp; + struct re_registers *regs; + unsigned num_regs; + regoff_t *starts, *ends; +{ + if (num_regs) + { + bufp->regs_allocated = REGS_REALLOCATE; + regs->num_regs = num_regs; + regs->start = starts; + regs->end = ends; + } + else + { + bufp->regs_allocated = REGS_UNALLOCATED; + regs->num_regs = 0; + regs->start = regs->end = (regoff_t *) 0; + } +} +WEAK_ALIAS (__re_set_registers, re_set_registers) + +/* Searching routines. */ + +/* Like re_search_2, below, but only one string is specified, and + doesn't let you say where to stop matching. */ + +int +re_search (bufp, string, size, startpos, range, regs) + struct re_pattern_buffer *bufp; + const char *string; + int size, startpos, range; + struct re_registers *regs; +{ + return re_search_2 (bufp, NULL, 0, string, size, startpos, range, + regs, size); +} +WEAK_ALIAS (__re_search, re_search) + +/* Head address of virtual concatenation of string. */ +#define HEAD_ADDR_VSTRING(P) \ + (((P) >= size1 ? string2 : string1)) + +/* End address of virtual concatenation of string. */ +#define STOP_ADDR_VSTRING(P) \ + (((P) >= size1 ? string2 + size2 : string1 + size1)) + +/* Address of POS in the concatenation of virtual string. */ +#define POS_ADDR_VSTRING(POS) \ + (((POS) >= size1 ? string2 - size1 : string1) + (POS)) + +/* Using the compiled pattern in BUFP->buffer, first tries to match the + virtual concatenation of STRING1 and STRING2, starting first at index + STARTPOS, then at STARTPOS + 1, and so on. + + STRING1 and STRING2 have length SIZE1 and SIZE2, respectively. + + RANGE is how far to scan while trying to match. RANGE = 0 means try + only at STARTPOS; in general, the last start tried is STARTPOS + + RANGE. + + In REGS, return the indices of the virtual concatenation of STRING1 + and STRING2 that matched the entire BUFP->buffer and its contained + subexpressions. + + Do not consider matching one past the index STOP in the virtual + concatenation of STRING1 and STRING2. + + We return either the position in the strings at which the match was + found, -1 if no match, or -2 if error (such as failure + stack overflow). */ + +int +re_search_2 (bufp, str1, size1, str2, size2, startpos, range, regs, stop) + struct re_pattern_buffer *bufp; + const char *str1, *str2; + int size1, size2; + int startpos; + int range; + struct re_registers *regs; + int stop; +{ + int val; + re_char *string1 = (re_char*) str1; + re_char *string2 = (re_char*) str2; + register char *fastmap = bufp->fastmap; + register RE_TRANSLATE_TYPE translate = bufp->translate; + int total_size = size1 + size2; + int endpos = startpos + range; + boolean anchored_start; + + /* Nonzero if we have to concern multibyte character. */ + const boolean multibyte = RE_MULTIBYTE_P (bufp); + + /* Check for out-of-range STARTPOS. */ + if (startpos < 0 || startpos > total_size) + return -1; + + /* Fix up RANGE if it might eventually take us outside + the virtual concatenation of STRING1 and STRING2. + Make sure we won't move STARTPOS below 0 or above TOTAL_SIZE. */ + if (endpos < 0) + range = 0 - startpos; + else if (endpos > total_size) + range = total_size - startpos; + + /* If the search isn't to be a backwards one, don't waste time in a + search for a pattern anchored at beginning of buffer. */ + if (bufp->used > 0 && (re_opcode_t) bufp->buffer[0] == begbuf && range > 0) + { + if (startpos > 0) + return -1; + else + range = 0; + } + +#ifdef emacs + /* In a forward search for something that starts with \=. + don't keep searching past point. */ + if (bufp->used > 0 && (re_opcode_t) bufp->buffer[0] == at_dot && range > 0) + { + range = PT_BYTE - BEGV_BYTE - startpos; + if (range < 0) + return -1; + } +#endif /* emacs */ + + /* Update the fastmap now if not correct already. */ + if (fastmap && !bufp->fastmap_accurate) + re_compile_fastmap (bufp); + + /* See whether the pattern is anchored. */ + anchored_start = (bufp->buffer[0] == begline); + +#ifdef emacs + gl_state.object = re_match_object; + { + int charpos = SYNTAX_TABLE_BYTE_TO_CHAR (POS_AS_IN_BUFFER (startpos)); + + SETUP_SYNTAX_TABLE_FOR_OBJECT (re_match_object, charpos, 1); + } +#endif + + /* Loop through the string, looking for a place to start matching. */ + for (;;) + { + /* If the pattern is anchored, + skip quickly past places we cannot match. + We don't bother to treat startpos == 0 specially + because that case doesn't repeat. */ + if (anchored_start && startpos > 0) + { + if (! ((startpos <= size1 ? string1[startpos - 1] + : string2[startpos - size1 - 1]) + == '\n')) + goto advance; + } + + /* If a fastmap is supplied, skip quickly over characters that + cannot be the start of a match. If the pattern can match the + null string, however, we don't need to skip characters; we want + the first null string. */ + if (fastmap && startpos < total_size && !bufp->can_be_null) + { + register re_char *d; + register re_wchar_t buf_ch; + + d = POS_ADDR_VSTRING (startpos); + + if (range > 0) /* Searching forwards. */ + { + register int lim = 0; + int irange = range; + + if (startpos < size1 && startpos + range >= size1) + lim = range - (size1 - startpos); + + /* Written out as an if-else to avoid testing `translate' + inside the loop. */ + if (RE_TRANSLATE_P (translate)) + { + if (multibyte) + while (range > lim) + { + int buf_charlen; + + buf_ch = STRING_CHAR_AND_LENGTH (d, range - lim, + buf_charlen); + + buf_ch = RE_TRANSLATE (translate, buf_ch); + if (buf_ch >= 0400 + || fastmap[buf_ch]) + break; + + range -= buf_charlen; + d += buf_charlen; + } + else + while (range > lim + && !fastmap[RE_TRANSLATE (translate, *d)]) + { + d++; + range--; + } + } + else + while (range > lim && !fastmap[*d]) + { + d++; + range--; + } + + startpos += irange - range; + } + else /* Searching backwards. */ + { + int room = (startpos >= size1 + ? size2 + size1 - startpos + : size1 - startpos); + buf_ch = RE_STRING_CHAR (d, room); + buf_ch = TRANSLATE (buf_ch); + + if (! (buf_ch >= 0400 + || fastmap[buf_ch])) + goto advance; + } + } + + /* If can't match the null string, and that's all we have left, fail. */ + if (range >= 0 && startpos == total_size && fastmap + && !bufp->can_be_null) + return -1; + + val = re_match_2_internal (bufp, string1, size1, string2, size2, + startpos, regs, stop); +#ifndef REGEX_MALLOC +# ifdef C_ALLOCA + alloca (0); +# endif +#endif + + if (val >= 0) + return startpos; + + if (val == -2) + return -2; + + advance: + if (!range) + break; + else if (range > 0) + { + /* Update STARTPOS to the next character boundary. */ + if (multibyte) + { + re_char *p = POS_ADDR_VSTRING (startpos); + re_char *pend = STOP_ADDR_VSTRING (startpos); + int len = MULTIBYTE_FORM_LENGTH (p, pend - p); + + range -= len; + if (range < 0) + break; + startpos += len; + } + else + { + range--; + startpos++; + } + } + else + { + range++; + startpos--; + + /* Update STARTPOS to the previous character boundary. */ + if (multibyte) + { + re_char *p = POS_ADDR_VSTRING (startpos) + 1; + re_char *p0 = p; + re_char *phead = HEAD_ADDR_VSTRING (startpos); + + /* Find the head of multibyte form. */ + PREV_CHAR_BOUNDARY (p, phead); + range += p0 - 1 - p; + if (range > 0) + break; + + startpos -= p0 - 1 - p; + } + } + } + return -1; +} /* re_search_2 */ +WEAK_ALIAS (__re_search_2, re_search_2) + +/* Declarations and macros for re_match_2. */ + +static int bcmp_translate _RE_ARGS((re_char *s1, re_char *s2, + register int len, + RE_TRANSLATE_TYPE translate, + const int multibyte)); + +/* This converts PTR, a pointer into one of the search strings `string1' + and `string2' into an offset from the beginning of that string. */ +#define POINTER_TO_OFFSET(ptr) \ + (FIRST_STRING_P (ptr) \ + ? ((regoff_t) ((ptr) - string1)) \ + : ((regoff_t) ((ptr) - string2 + size1))) + +/* Call before fetching a character with *d. This switches over to + string2 if necessary. + Check re_match_2_internal for a discussion of why end_match_2 might + not be within string2 (but be equal to end_match_1 instead). */ +#define PREFETCH() \ + while (d == dend) \ + { \ + /* End of string2 => fail. */ \ + if (dend == end_match_2) \ + goto fail; \ + /* End of string1 => advance to string2. */ \ + d = string2; \ + dend = end_match_2; \ + } + +/* Call before fetching a char with *d if you already checked other limits. + This is meant for use in lookahead operations like wordend, etc.. + where we might need to look at parts of the string that might be + outside of the LIMITs (i.e past `stop'). */ +#define PREFETCH_NOLIMIT() \ + if (d == end1) \ + { \ + d = string2; \ + dend = end_match_2; \ + } \ + +/* Test if at very beginning or at very end of the virtual concatenation + of `string1' and `string2'. If only one string, it's `string2'. */ +#define AT_STRINGS_BEG(d) ((d) == (size1 ? string1 : string2) || !size2) +#define AT_STRINGS_END(d) ((d) == end2) + + +/* Test if D points to a character which is word-constituent. We have + two special cases to check for: if past the end of string1, look at + the first character in string2; and if before the beginning of + string2, look at the last character in string1. */ +#define WORDCHAR_P(d) \ + (SYNTAX ((d) == end1 ? *string2 \ + : (d) == string2 - 1 ? *(end1 - 1) : *(d)) \ + == Sword) + +/* Disabled due to a compiler bug -- see comment at case wordbound */ + +/* The comment at case wordbound is following one, but we don't use + AT_WORD_BOUNDARY anymore to support multibyte form. + + The DEC Alpha C compiler 3.x generates incorrect code for the + test WORDCHAR_P (d - 1) != WORDCHAR_P (d) in the expansion of + AT_WORD_BOUNDARY, so this code is disabled. Expanding the + macro and introducing temporary variables works around the bug. */ + +#if 0 +/* Test if the character before D and the one at D differ with respect + to being word-constituent. */ +#define AT_WORD_BOUNDARY(d) \ + (AT_STRINGS_BEG (d) || AT_STRINGS_END (d) \ + || WORDCHAR_P (d - 1) != WORDCHAR_P (d)) +#endif + +/* Free everything we malloc. */ +#ifdef MATCH_MAY_ALLOCATE +# define FREE_VAR(var) if (var) { REGEX_FREE (var); var = NULL; } else +# define FREE_VARIABLES() \ + do { \ + REGEX_FREE_STACK (fail_stack.stack); \ + FREE_VAR (regstart); \ + FREE_VAR (regend); \ + FREE_VAR (best_regstart); \ + FREE_VAR (best_regend); \ + } while (0) +#else +# define FREE_VARIABLES() ((void)0) /* Do nothing! But inhibit gcc warning. */ +#endif /* not MATCH_MAY_ALLOCATE */ + + +/* Optimization routines. */ + +/* If the operation is a match against one or more chars, + return a pointer to the next operation, else return NULL. */ +static re_char * +skip_one_char (p) + re_char *p; +{ + switch (SWITCH_ENUM_CAST (*p++)) + { + case anychar: + break; + + case exactn: + p += *p + 1; + break; + + case charset_not: + case charset: + if (CHARSET_RANGE_TABLE_EXISTS_P (p - 1)) + { + int mcnt; + p = CHARSET_RANGE_TABLE (p - 1); + EXTRACT_NUMBER_AND_INCR (mcnt, p); + p = CHARSET_RANGE_TABLE_END (p, mcnt); + } + else + p += 1 + CHARSET_BITMAP_SIZE (p - 1); + break; + + case syntaxspec: + case notsyntaxspec: +#ifdef emacs + case categoryspec: + case notcategoryspec: +#endif /* emacs */ + p++; + break; + + default: + p = NULL; + } + return p; +} + + +/* Jump over non-matching operations. */ +static re_char * +skip_noops (p, pend) + re_char *p, *pend; +{ + int mcnt; + while (p < pend) + { + switch (SWITCH_ENUM_CAST ((re_opcode_t) *p)) + { + case start_memory: + case stop_memory: + p += 2; break; + case no_op: + p += 1; break; + case jump: + p += 1; + EXTRACT_NUMBER_AND_INCR (mcnt, p); + p += mcnt; + break; + default: + return p; + } + } + assert (p == pend); + return p; +} + +/* Non-zero if "p1 matches something" implies "p2 fails". */ +static int +mutually_exclusive_p (bufp, p1, p2) + struct re_pattern_buffer *bufp; + re_char *p1, *p2; +{ + re_opcode_t op2; + const boolean multibyte = RE_MULTIBYTE_P (bufp); + unsigned char *pend = bufp->buffer + bufp->used; + + assert (p1 >= bufp->buffer && p1 < pend + && p2 >= bufp->buffer && p2 <= pend); + + /* Skip over open/close-group commands. + If what follows this loop is a ...+ construct, + look at what begins its body, since we will have to + match at least one of that. */ + p2 = skip_noops (p2, pend); + /* The same skip can be done for p1, except that this function + is only used in the case where p1 is a simple match operator. */ + /* p1 = skip_noops (p1, pend); */ + + assert (p1 >= bufp->buffer && p1 < pend + && p2 >= bufp->buffer && p2 <= pend); + + op2 = p2 == pend ? succeed : *p2; + + switch (SWITCH_ENUM_CAST (op2)) + { + case succeed: + case endbuf: + /* If we're at the end of the pattern, we can change. */ + if (skip_one_char (p1)) + { + DEBUG_PRINT1 (" End of pattern: fast loop.\n"); + return 1; + } + break; + + case endline: + case exactn: + { + register re_wchar_t c + = (re_opcode_t) *p2 == endline ? '\n' + : RE_STRING_CHAR (p2 + 2, pend - p2 - 2); + + if ((re_opcode_t) *p1 == exactn) + { + if (c != RE_STRING_CHAR (p1 + 2, pend - p1 - 2)) + { + DEBUG_PRINT3 (" '%c' != '%c' => fast loop.\n", c, p1[2]); + return 1; + } + } + + else if ((re_opcode_t) *p1 == charset + || (re_opcode_t) *p1 == charset_not) + { + int not = (re_opcode_t) *p1 == charset_not; + + /* Test if C is listed in charset (or charset_not) + at `p1'. */ + if (SINGLE_BYTE_CHAR_P (c)) + { + if (c < CHARSET_BITMAP_SIZE (p1) * BYTEWIDTH + && p1[2 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH))) + not = !not; + } + else if (CHARSET_RANGE_TABLE_EXISTS_P (p1)) + CHARSET_LOOKUP_RANGE_TABLE (not, c, p1); + + /* `not' is equal to 1 if c would match, which means + that we can't change to pop_failure_jump. */ + if (!not) + { + DEBUG_PRINT1 (" No match => fast loop.\n"); + return 1; + } + } + else if ((re_opcode_t) *p1 == anychar + && c == '\n') + { + DEBUG_PRINT1 (" . != \\n => fast loop.\n"); + return 1; + } + } + break; + + case charset: + { + if ((re_opcode_t) *p1 == exactn) + /* Reuse the code above. */ + return mutually_exclusive_p (bufp, p2, p1); + + /* It is hard to list up all the character in charset + P2 if it includes multibyte character. Give up in + such case. */ + else if (!multibyte || !CHARSET_RANGE_TABLE_EXISTS_P (p2)) + { + /* Now, we are sure that P2 has no range table. + So, for the size of bitmap in P2, `p2[1]' is + enough. But P1 may have range table, so the + size of bitmap table of P1 is extracted by + using macro `CHARSET_BITMAP_SIZE'. + + Since we know that all the character listed in + P2 is ASCII, it is enough to test only bitmap + table of P1. */ + + if ((re_opcode_t) *p1 == charset) + { + int idx; + /* We win if the charset inside the loop + has no overlap with the one after the loop. */ + for (idx = 0; + (idx < (int) p2[1] + && idx < CHARSET_BITMAP_SIZE (p1)); + idx++) + if ((p2[2 + idx] & p1[2 + idx]) != 0) + break; + + if (idx == p2[1] + || idx == CHARSET_BITMAP_SIZE (p1)) + { + DEBUG_PRINT1 (" No match => fast loop.\n"); + return 1; + } + } + else if ((re_opcode_t) *p1 == charset_not) + { + int idx; + /* We win if the charset_not inside the loop lists + every character listed in the charset after. */ + for (idx = 0; idx < (int) p2[1]; idx++) + if (! (p2[2 + idx] == 0 + || (idx < CHARSET_BITMAP_SIZE (p1) + && ((p2[2 + idx] & ~ p1[2 + idx]) == 0)))) + break; + + if (idx == p2[1]) + { + DEBUG_PRINT1 (" No match => fast loop.\n"); + return 1; + } + } + } + } + break; + + case charset_not: + switch (SWITCH_ENUM_CAST (*p1)) + { + case exactn: + case charset: + /* Reuse the code above. */ + return mutually_exclusive_p (bufp, p2, p1); + case charset_not: + /* When we have two charset_not, it's very unlikely that + they don't overlap. The union of the two sets of excluded + chars should cover all possible chars, which, as a matter of + fact, is virtually impossible in multibyte buffers. */ + break; + } + break; + + case wordend: + case notsyntaxspec: + return ((re_opcode_t) *p1 == syntaxspec + && p1[1] == (op2 == wordend ? Sword : p2[1])); + + case wordbeg: + case syntaxspec: + return ((re_opcode_t) *p1 == notsyntaxspec + && p1[1] == (op2 == wordend ? Sword : p2[1])); + + case wordbound: + return (((re_opcode_t) *p1 == notsyntaxspec + || (re_opcode_t) *p1 == syntaxspec) + && p1[1] == Sword); + +#ifdef emacs + case categoryspec: + return ((re_opcode_t) *p1 == notcategoryspec && p1[1] == p2[1]); + case notcategoryspec: + return ((re_opcode_t) *p1 == categoryspec && p1[1] == p2[1]); +#endif /* emacs */ + + default: + ; + } + + /* Safe default. */ + return 0; +} + + +/* Matching routines. */ + +#ifndef emacs /* Emacs never uses this. */ +/* re_match is like re_match_2 except it takes only a single string. */ + +int +re_match (bufp, string, size, pos, regs) + struct re_pattern_buffer *bufp; + const char *string; + int size, pos; + struct re_registers *regs; +{ + int result = re_match_2_internal (bufp, NULL, 0, (re_char*) string, size, + pos, regs, size); +# if defined C_ALLOCA && !defined REGEX_MALLOC + alloca (0); +# endif + return result; +} +WEAK_ALIAS (__re_match, re_match) +#endif /* not emacs */ + +#ifdef emacs +/* In Emacs, this is the string or buffer in which we + are matching. It is used for looking up syntax properties. */ +Lisp_Object re_match_object; +#endif + +/* re_match_2 matches the compiled pattern in BUFP against the + the (virtual) concatenation of STRING1 and STRING2 (of length SIZE1 + and SIZE2, respectively). We start matching at POS, and stop + matching at STOP. + + If REGS is non-null and the `no_sub' field of BUFP is nonzero, we + store offsets for the substring each group matched in REGS. See the + documentation for exactly how many groups we fill. + + We return -1 if no match, -2 if an internal error (such as the + failure stack overflowing). Otherwise, we return the length of the + matched substring. */ + +int +re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) + struct re_pattern_buffer *bufp; + const char *string1, *string2; + int size1, size2; + int pos; + struct re_registers *regs; + int stop; +{ + int result; + +#ifdef emacs + int charpos; + gl_state.object = re_match_object; + charpos = SYNTAX_TABLE_BYTE_TO_CHAR (POS_AS_IN_BUFFER (pos)); + SETUP_SYNTAX_TABLE_FOR_OBJECT (re_match_object, charpos, 1); +#endif + + result = re_match_2_internal (bufp, (re_char*) string1, size1, + (re_char*) string2, size2, + pos, regs, stop); +#if defined C_ALLOCA && !defined REGEX_MALLOC + alloca (0); +#endif + return result; +} +WEAK_ALIAS (__re_match_2, re_match_2) + +/* This is a separate function so that we can force an alloca cleanup + afterwards. */ +static int +re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop) + struct re_pattern_buffer *bufp; + re_char *string1, *string2; + int size1, size2; + int pos; + struct re_registers *regs; + int stop; +{ + /* General temporaries. */ + int mcnt; + size_t reg; + boolean not; + + /* Just past the end of the corresponding string. */ + re_char *end1, *end2; + + /* Pointers into string1 and string2, just past the last characters in + each to consider matching. */ + re_char *end_match_1, *end_match_2; + + /* Where we are in the data, and the end of the current string. */ + re_char *d, *dend; + + /* Used sometimes to remember where we were before starting matching + an operator so that we can go back in case of failure. This "atomic" + behavior of matching opcodes is indispensable to the correctness + of the on_failure_keep_string_jump optimization. */ + re_char *dfail; + + /* Where we are in the pattern, and the end of the pattern. */ + re_char *p = bufp->buffer; + re_char *pend = p + bufp->used; + + /* We use this to map every character in the string. */ + RE_TRANSLATE_TYPE translate = bufp->translate; + + /* Nonzero if we have to concern multibyte character. */ + const boolean multibyte = RE_MULTIBYTE_P (bufp); + + /* Failure point stack. Each place that can handle a failure further + down the line pushes a failure point on this stack. It consists of + regstart, and regend for all registers corresponding to + the subexpressions we're currently inside, plus the number of such + registers, and, finally, two char *'s. The first char * is where + to resume scanning the pattern; the second one is where to resume + scanning the strings. */ +#ifdef MATCH_MAY_ALLOCATE /* otherwise, this is global. */ + fail_stack_type fail_stack; +#endif +#ifdef DEBUG + unsigned nfailure_points_pushed = 0, nfailure_points_popped = 0; +#endif + +#if defined REL_ALLOC && defined REGEX_MALLOC + /* This holds the pointer to the failure stack, when + it is allocated relocatably. */ + fail_stack_elt_t *failure_stack_ptr; +#endif + + /* We fill all the registers internally, independent of what we + return, for use in backreferences. The number here includes + an element for register zero. */ + size_t num_regs = bufp->re_nsub + 1; + + /* Information on the contents of registers. These are pointers into + the input strings; they record just what was matched (on this + attempt) by a subexpression part of the pattern, that is, the + regnum-th regstart pointer points to where in the pattern we began + matching and the regnum-th regend points to right after where we + stopped matching the regnum-th subexpression. (The zeroth register + keeps track of what the whole pattern matches.) */ +#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */ + re_char **regstart, **regend; +#endif + + /* The following record the register info as found in the above + variables when we find a match better than any we've seen before. + This happens as we backtrack through the failure points, which in + turn happens only if we have not yet matched the entire string. */ + unsigned best_regs_set = false; +#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */ + re_char **best_regstart, **best_regend; +#endif + + /* Logically, this is `best_regend[0]'. But we don't want to have to + allocate space for that if we're not allocating space for anything + else (see below). Also, we never need info about register 0 for + any of the other register vectors, and it seems rather a kludge to + treat `best_regend' differently than the rest. So we keep track of + the end of the best match so far in a separate variable. We + initialize this to NULL so that when we backtrack the first time + and need to test it, it's not garbage. */ + re_char *match_end = NULL; + +#ifdef DEBUG + /* Counts the total number of registers pushed. */ + unsigned num_regs_pushed = 0; +#endif + + DEBUG_PRINT1 ("\n\nEntering re_match_2.\n"); + + INIT_FAIL_STACK (); + +#ifdef MATCH_MAY_ALLOCATE + /* Do not bother to initialize all the register variables if there are + no groups in the pattern, as it takes a fair amount of time. If + there are groups, we include space for register 0 (the whole + pattern), even though we never use it, since it simplifies the + array indexing. We should fix this. */ + if (bufp->re_nsub) + { + regstart = REGEX_TALLOC (num_regs, re_char *); + regend = REGEX_TALLOC (num_regs, re_char *); + best_regstart = REGEX_TALLOC (num_regs, re_char *); + best_regend = REGEX_TALLOC (num_regs, re_char *); + + if (!(regstart && regend && best_regstart && best_regend)) + { + FREE_VARIABLES (); + return -2; + } + } + else + { + /* We must initialize all our variables to NULL, so that + `FREE_VARIABLES' doesn't try to free them. */ + regstart = regend = best_regstart = best_regend = NULL; + } +#endif /* MATCH_MAY_ALLOCATE */ + + /* The starting position is bogus. */ + if (pos < 0 || pos > size1 + size2) + { + FREE_VARIABLES (); + return -1; + } + + /* Initialize subexpression text positions to -1 to mark ones that no + start_memory/stop_memory has been seen for. Also initialize the + register information struct. */ + for (reg = 1; reg < num_regs; reg++) + regstart[reg] = regend[reg] = NULL; + + /* We move `string1' into `string2' if the latter's empty -- but not if + `string1' is null. */ + if (size2 == 0 && string1 != NULL) + { + string2 = string1; + size2 = size1; + string1 = 0; + size1 = 0; + } + end1 = string1 + size1; + end2 = string2 + size2; + + /* `p' scans through the pattern as `d' scans through the data. + `dend' is the end of the input string that `d' points within. `d' + is advanced into the following input string whenever necessary, but + this happens before fetching; therefore, at the beginning of the + loop, `d' can be pointing at the end of a string, but it cannot + equal `string2'. */ + if (pos >= size1) + { + /* Only match within string2. */ + d = string2 + pos - size1; + dend = end_match_2 = string2 + stop - size1; + end_match_1 = end1; /* Just to give it a value. */ + } + else + { + if (stop < size1) + { + /* Only match within string1. */ + end_match_1 = string1 + stop; + /* BEWARE! + When we reach end_match_1, PREFETCH normally switches to string2. + But in the present case, this means that just doing a PREFETCH + makes us jump from `stop' to `gap' within the string. + What we really want here is for the search to stop as + soon as we hit end_match_1. That's why we set end_match_2 + to end_match_1 (since PREFETCH fails as soon as we hit + end_match_2). */ + end_match_2 = end_match_1; + } + else + { /* It's important to use this code when stop == size so that + moving `d' from end1 to string2 will not prevent the d == dend + check from catching the end of string. */ + end_match_1 = end1; + end_match_2 = string2 + stop - size1; + } + d = string1 + pos; + dend = end_match_1; + } + + DEBUG_PRINT1 ("The compiled pattern is: "); + DEBUG_PRINT_COMPILED_PATTERN (bufp, p, pend); + DEBUG_PRINT1 ("The string to match is: `"); + DEBUG_PRINT_DOUBLE_STRING (d, string1, size1, string2, size2); + DEBUG_PRINT1 ("'\n"); + + /* This loops over pattern commands. It exits by returning from the + function if the match is complete, or it drops through if the match + fails at this starting point in the input data. */ + for (;;) + { + DEBUG_PRINT2 ("\n%p: ", p); + + if (p == pend) + { /* End of pattern means we might have succeeded. */ + DEBUG_PRINT1 ("end of pattern ... "); + + /* If we haven't matched the entire string, and we want the + longest match, try backtracking. */ + if (d != end_match_2) + { + /* 1 if this match ends in the same string (string1 or string2) + as the best previous match. */ + boolean same_str_p = (FIRST_STRING_P (match_end) + == FIRST_STRING_P (d)); + /* 1 if this match is the best seen so far. */ + boolean best_match_p; + + /* AIX compiler got confused when this was combined + with the previous declaration. */ + if (same_str_p) + best_match_p = d > match_end; + else + best_match_p = !FIRST_STRING_P (d); + + DEBUG_PRINT1 ("backtracking.\n"); + + if (!FAIL_STACK_EMPTY ()) + { /* More failure points to try. */ + + /* If exceeds best match so far, save it. */ + if (!best_regs_set || best_match_p) + { + best_regs_set = true; + match_end = d; + + DEBUG_PRINT1 ("\nSAVING match as best so far.\n"); + + for (reg = 1; reg < num_regs; reg++) + { + best_regstart[reg] = regstart[reg]; + best_regend[reg] = regend[reg]; + } + } + goto fail; + } + + /* If no failure points, don't restore garbage. And if + last match is real best match, don't restore second + best one. */ + else if (best_regs_set && !best_match_p) + { + restore_best_regs: + /* Restore best match. It may happen that `dend == + end_match_1' while the restored d is in string2. + For example, the pattern `x.*y.*z' against the + strings `x-' and `y-z-', if the two strings are + not consecutive in memory. */ + DEBUG_PRINT1 ("Restoring best registers.\n"); + + d = match_end; + dend = ((d >= string1 && d <= end1) + ? end_match_1 : end_match_2); + + for (reg = 1; reg < num_regs; reg++) + { + regstart[reg] = best_regstart[reg]; + regend[reg] = best_regend[reg]; + } + } + } /* d != end_match_2 */ + + succeed_label: + DEBUG_PRINT1 ("Accepting match.\n"); + + /* If caller wants register contents data back, do it. */ + if (regs && !bufp->no_sub) + { + /* Have the register data arrays been allocated? */ + if (bufp->regs_allocated == REGS_UNALLOCATED) + { /* No. So allocate them with malloc. We need one + extra element beyond `num_regs' for the `-1' marker + GNU code uses. */ + regs->num_regs = MAX (RE_NREGS, num_regs + 1); + regs->start = TALLOC (regs->num_regs, regoff_t); + regs->end = TALLOC (regs->num_regs, regoff_t); + if (regs->start == NULL || regs->end == NULL) + { + FREE_VARIABLES (); + return -2; + } + bufp->regs_allocated = REGS_REALLOCATE; + } + else if (bufp->regs_allocated == REGS_REALLOCATE) + { /* Yes. If we need more elements than were already + allocated, reallocate them. If we need fewer, just + leave it alone. */ + if (regs->num_regs < num_regs + 1) + { + regs->num_regs = num_regs + 1; + RETALLOC (regs->start, regs->num_regs, regoff_t); + RETALLOC (regs->end, regs->num_regs, regoff_t); + if (regs->start == NULL || regs->end == NULL) + { + FREE_VARIABLES (); + return -2; + } + } + } + else + { + /* These braces fend off a "empty body in an else-statement" + warning under GCC when assert expands to nothing. */ + assert (bufp->regs_allocated == REGS_FIXED); + } + + /* Convert the pointer data in `regstart' and `regend' to + indices. Register zero has to be set differently, + since we haven't kept track of any info for it. */ + if (regs->num_regs > 0) + { + regs->start[0] = pos; + regs->end[0] = POINTER_TO_OFFSET (d); + } + + /* Go through the first `min (num_regs, regs->num_regs)' + registers, since that is all we initialized. */ + for (reg = 1; reg < MIN (num_regs, regs->num_regs); reg++) + { + if (REG_UNSET (regstart[reg]) || REG_UNSET (regend[reg])) + regs->start[reg] = regs->end[reg] = -1; + else + { + regs->start[reg] + = (regoff_t) POINTER_TO_OFFSET (regstart[reg]); + regs->end[reg] + = (regoff_t) POINTER_TO_OFFSET (regend[reg]); + } + } + + /* If the regs structure we return has more elements than + were in the pattern, set the extra elements to -1. If + we (re)allocated the registers, this is the case, + because we always allocate enough to have at least one + -1 at the end. */ + for (reg = num_regs; reg < regs->num_regs; reg++) + regs->start[reg] = regs->end[reg] = -1; + } /* regs && !bufp->no_sub */ + + DEBUG_PRINT4 ("%u failure points pushed, %u popped (%u remain).\n", + nfailure_points_pushed, nfailure_points_popped, + nfailure_points_pushed - nfailure_points_popped); + DEBUG_PRINT2 ("%u registers pushed.\n", num_regs_pushed); + + mcnt = POINTER_TO_OFFSET (d) - pos; + + DEBUG_PRINT2 ("Returning %d from re_match_2.\n", mcnt); + + FREE_VARIABLES (); + return mcnt; + } + + /* Otherwise match next pattern command. */ + switch (SWITCH_ENUM_CAST ((re_opcode_t) *p++)) + { + /* Ignore these. Used to ignore the n of succeed_n's which + currently have n == 0. */ + case no_op: + DEBUG_PRINT1 ("EXECUTING no_op.\n"); + break; + + case succeed: + DEBUG_PRINT1 ("EXECUTING succeed.\n"); + goto succeed_label; + + /* Match the next n pattern characters exactly. The following + byte in the pattern defines n, and the n bytes after that + are the characters to match. */ + case exactn: + mcnt = *p++; + DEBUG_PRINT2 ("EXECUTING exactn %d.\n", mcnt); + + /* Remember the start point to rollback upon failure. */ + dfail = d; + + /* This is written out as an if-else so we don't waste time + testing `translate' inside the loop. */ + if (RE_TRANSLATE_P (translate)) + { + if (multibyte) + do + { + int pat_charlen, buf_charlen; + unsigned int pat_ch, buf_ch; + + PREFETCH (); + pat_ch = STRING_CHAR_AND_LENGTH (p, pend - p, pat_charlen); + buf_ch = STRING_CHAR_AND_LENGTH (d, dend - d, buf_charlen); + + if (RE_TRANSLATE (translate, buf_ch) + != pat_ch) + { + d = dfail; + goto fail; + } + + p += pat_charlen; + d += buf_charlen; + mcnt -= pat_charlen; + } + while (mcnt > 0); + else + do + { + PREFETCH (); + if (RE_TRANSLATE (translate, *d) != *p++) + { + d = dfail; + goto fail; + } + d++; + } + while (--mcnt); + } + else + { + do + { + PREFETCH (); + if (*d++ != *p++) + { + d = dfail; + goto fail; + } + } + while (--mcnt); + } + break; + + + /* Match any character except possibly a newline or a null. */ + case anychar: + { + int buf_charlen; + re_wchar_t buf_ch; + + DEBUG_PRINT1 ("EXECUTING anychar.\n"); + + PREFETCH (); + buf_ch = RE_STRING_CHAR_AND_LENGTH (d, dend - d, buf_charlen); + buf_ch = TRANSLATE (buf_ch); + + if ((!(bufp->syntax & RE_DOT_NEWLINE) + && buf_ch == '\n') + || ((bufp->syntax & RE_DOT_NOT_NULL) + && buf_ch == '\000')) + goto fail; + + DEBUG_PRINT2 (" Matched `%d'.\n", *d); + d += buf_charlen; + } + break; + + + case charset: + case charset_not: + { + register unsigned int c; + boolean not = (re_opcode_t) *(p - 1) == charset_not; + int len; + + /* Start of actual range_table, or end of bitmap if there is no + range table. */ + re_char *range_table; + + /* Nonzero if there is a range table. */ + int range_table_exists; + + /* Number of ranges of range table. This is not included + in the initial byte-length of the command. */ + int count = 0; + + DEBUG_PRINT2 ("EXECUTING charset%s.\n", not ? "_not" : ""); + + range_table_exists = CHARSET_RANGE_TABLE_EXISTS_P (&p[-1]); + + if (range_table_exists) + { + range_table = CHARSET_RANGE_TABLE (&p[-1]); /* Past the bitmap. */ + EXTRACT_NUMBER_AND_INCR (count, range_table); + } + + PREFETCH (); + c = RE_STRING_CHAR_AND_LENGTH (d, dend - d, len); + c = TRANSLATE (c); /* The character to match. */ + + if (SINGLE_BYTE_CHAR_P (c)) + { /* Lookup bitmap. */ + /* Cast to `unsigned' instead of `unsigned char' in + case the bit list is a full 32 bytes long. */ + if (c < (unsigned) (CHARSET_BITMAP_SIZE (&p[-1]) * BYTEWIDTH) + && p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH))) + not = !not; + } +#ifdef emacs + else if (range_table_exists) + { + int class_bits = CHARSET_RANGE_TABLE_BITS (&p[-1]); + + if ( (class_bits & BIT_LOWER && ISLOWER (c)) + | (class_bits & BIT_MULTIBYTE) + | (class_bits & BIT_PUNCT && ISPUNCT (c)) + | (class_bits & BIT_SPACE && ISSPACE (c)) + | (class_bits & BIT_UPPER && ISUPPER (c)) + | (class_bits & BIT_WORD && ISWORD (c))) + not = !not; + else + CHARSET_LOOKUP_RANGE_TABLE_RAW (not, c, range_table, count); + } +#endif /* emacs */ + + if (range_table_exists) + p = CHARSET_RANGE_TABLE_END (range_table, count); + else + p += CHARSET_BITMAP_SIZE (&p[-1]) + 1; + + if (!not) goto fail; + + d += len; + break; + } + + + /* The beginning of a group is represented by start_memory. + The argument is the register number. The text + matched within the group is recorded (in the internal + registers data structure) under the register number. */ + case start_memory: + DEBUG_PRINT2 ("EXECUTING start_memory %d:\n", *p); + + /* In case we need to undo this operation (via backtracking). */ + PUSH_FAILURE_REG ((unsigned int)*p); + + regstart[*p] = d; + regend[*p] = NULL; /* probably unnecessary. -sm */ + DEBUG_PRINT2 (" regstart: %d\n", POINTER_TO_OFFSET (regstart[*p])); + + /* Move past the register number and inner group count. */ + p += 1; + break; + + + /* The stop_memory opcode represents the end of a group. Its + argument is the same as start_memory's: the register number. */ + case stop_memory: + DEBUG_PRINT2 ("EXECUTING stop_memory %d:\n", *p); + + assert (!REG_UNSET (regstart[*p])); + /* Strictly speaking, there should be code such as: + + assert (REG_UNSET (regend[*p])); + PUSH_FAILURE_REGSTOP ((unsigned int)*p); + + But the only info to be pushed is regend[*p] and it is known to + be UNSET, so there really isn't anything to push. + Not pushing anything, on the other hand deprives us from the + guarantee that regend[*p] is UNSET since undoing this operation + will not reset its value properly. This is not important since + the value will only be read on the next start_memory or at + the very end and both events can only happen if this stop_memory + is *not* undone. */ + + regend[*p] = d; + DEBUG_PRINT2 (" regend: %d\n", POINTER_TO_OFFSET (regend[*p])); + + /* Move past the register number and the inner group count. */ + p += 1; + break; + + + /* \<digit> has been turned into a `duplicate' command which is + followed by the numeric value of <digit> as the register number. */ + case duplicate: + { + register re_char *d2, *dend2; + int regno = *p++; /* Get which register to match against. */ + DEBUG_PRINT2 ("EXECUTING duplicate %d.\n", regno); + + /* Can't back reference a group which we've never matched. */ + if (REG_UNSET (regstart[regno]) || REG_UNSET (regend[regno])) + goto fail; + + /* Where in input to try to start matching. */ + d2 = regstart[regno]; + + /* Remember the start point to rollback upon failure. */ + dfail = d; + + /* Where to stop matching; if both the place to start and + the place to stop matching are in the same string, then + set to the place to stop, otherwise, for now have to use + the end of the first string. */ + + dend2 = ((FIRST_STRING_P (regstart[regno]) + == FIRST_STRING_P (regend[regno])) + ? regend[regno] : end_match_1); + for (;;) + { + /* If necessary, advance to next segment in register + contents. */ + while (d2 == dend2) + { + if (dend2 == end_match_2) break; + if (dend2 == regend[regno]) break; + + /* End of string1 => advance to string2. */ + d2 = string2; + dend2 = regend[regno]; + } + /* At end of register contents => success */ + if (d2 == dend2) break; + + /* If necessary, advance to next segment in data. */ + PREFETCH (); + + /* How many characters left in this segment to match. */ + mcnt = dend - d; + + /* Want how many consecutive characters we can match in + one shot, so, if necessary, adjust the count. */ + if (mcnt > dend2 - d2) + mcnt = dend2 - d2; + + /* Compare that many; failure if mismatch, else move + past them. */ + if (RE_TRANSLATE_P (translate) + ? bcmp_translate (d, d2, mcnt, translate, multibyte) + : memcmp (d, d2, mcnt)) + { + d = dfail; + goto fail; + } + d += mcnt, d2 += mcnt; + } + } + break; + + + /* begline matches the empty string at the beginning of the string + (unless `not_bol' is set in `bufp'), and after newlines. */ + case begline: + DEBUG_PRINT1 ("EXECUTING begline.\n"); + + if (AT_STRINGS_BEG (d)) + { + if (!bufp->not_bol) break; + } + else + { + unsigned char c; + GET_CHAR_BEFORE_2 (c, d, string1, end1, string2, end2); + if (c == '\n') + break; + } + /* In all other cases, we fail. */ + goto fail; + + + /* endline is the dual of begline. */ + case endline: + DEBUG_PRINT1 ("EXECUTING endline.\n"); + + if (AT_STRINGS_END (d)) + { + if (!bufp->not_eol) break; + } + else + { + PREFETCH_NOLIMIT (); + if (*d == '\n') + break; + } + goto fail; + + + /* Match at the very beginning of the data. */ + case begbuf: + DEBUG_PRINT1 ("EXECUTING begbuf.\n"); + if (AT_STRINGS_BEG (d)) + break; + goto fail; + + + /* Match at the very end of the data. */ + case endbuf: + DEBUG_PRINT1 ("EXECUTING endbuf.\n"); + if (AT_STRINGS_END (d)) + break; + goto fail; + + + /* on_failure_keep_string_jump is used to optimize `.*\n'. It + pushes NULL as the value for the string on the stack. Then + `POP_FAILURE_POINT' will keep the current value for the + string, instead of restoring it. To see why, consider + matching `foo\nbar' against `.*\n'. The .* matches the foo; + then the . fails against the \n. But the next thing we want + to do is match the \n against the \n; if we restored the + string value, we would be back at the foo. + + Because this is used only in specific cases, we don't need to + check all the things that `on_failure_jump' does, to make + sure the right things get saved on the stack. Hence we don't + share its code. The only reason to push anything on the + stack at all is that otherwise we would have to change + `anychar's code to do something besides goto fail in this + case; that seems worse than this. */ + case on_failure_keep_string_jump: + EXTRACT_NUMBER_AND_INCR (mcnt, p); + DEBUG_PRINT3 ("EXECUTING on_failure_keep_string_jump %d (to %p):\n", + mcnt, p + mcnt); + + PUSH_FAILURE_POINT (p - 3, NULL); + break; + + /* A nasty loop is introduced by the non-greedy *? and +?. + With such loops, the stack only ever contains one failure point + at a time, so that a plain on_failure_jump_loop kind of + cycle detection cannot work. Worse yet, such a detection + can not only fail to detect a cycle, but it can also wrongly + detect a cycle (between different instantiations of the same + loop). + So the method used for those nasty loops is a little different: + We use a special cycle-detection-stack-frame which is pushed + when the on_failure_jump_nastyloop failure-point is *popped*. + This special frame thus marks the beginning of one iteration + through the loop and we can hence easily check right here + whether something matched between the beginning and the end of + the loop. */ + case on_failure_jump_nastyloop: + EXTRACT_NUMBER_AND_INCR (mcnt, p); + DEBUG_PRINT3 ("EXECUTING on_failure_jump_nastyloop %d (to %p):\n", + mcnt, p + mcnt); + + assert ((re_opcode_t)p[-4] == no_op); + { + int cycle = 0; + CHECK_INFINITE_LOOP (p - 4, d); + if (!cycle) + /* If there's a cycle, just continue without pushing + this failure point. The failure point is the "try again" + option, which shouldn't be tried. + We want (x?)*?y\1z to match both xxyz and xxyxz. */ + PUSH_FAILURE_POINT (p - 3, d); + } + break; + + /* Simple loop detecting on_failure_jump: just check on the + failure stack if the same spot was already hit earlier. */ + case on_failure_jump_loop: + on_failure: + EXTRACT_NUMBER_AND_INCR (mcnt, p); + DEBUG_PRINT3 ("EXECUTING on_failure_jump_loop %d (to %p):\n", + mcnt, p + mcnt); + { + int cycle = 0; + CHECK_INFINITE_LOOP (p - 3, d); + if (cycle) + /* If there's a cycle, get out of the loop, as if the matching + had failed. We used to just `goto fail' here, but that was + aborting the search a bit too early: we want to keep the + empty-loop-match and keep matching after the loop. + We want (x?)*y\1z to match both xxyz and xxyxz. */ + p += mcnt; + else + PUSH_FAILURE_POINT (p - 3, d); + } + break; + + + /* Uses of on_failure_jump: + + Each alternative starts with an on_failure_jump that points + to the beginning of the next alternative. Each alternative + except the last ends with a jump that in effect jumps past + the rest of the alternatives. (They really jump to the + ending jump of the following alternative, because tensioning + these jumps is a hassle.) + + Repeats start with an on_failure_jump that points past both + the repetition text and either the following jump or + pop_failure_jump back to this on_failure_jump. */ + case on_failure_jump: + IMMEDIATE_QUIT_CHECK; + EXTRACT_NUMBER_AND_INCR (mcnt, p); + DEBUG_PRINT3 ("EXECUTING on_failure_jump %d (to %p):\n", + mcnt, p + mcnt); + + PUSH_FAILURE_POINT (p -3, d); + break; + + /* This operation is used for greedy *. + Compare the beginning of the repeat with what in the + pattern follows its end. If we can establish that there + is nothing that they would both match, i.e., that we + would have to backtrack because of (as in, e.g., `a*a') + then we can use a non-backtracking loop based on + on_failure_keep_string_jump instead of on_failure_jump. */ + case on_failure_jump_smart: + IMMEDIATE_QUIT_CHECK; + EXTRACT_NUMBER_AND_INCR (mcnt, p); + DEBUG_PRINT3 ("EXECUTING on_failure_jump_smart %d (to %p).\n", + mcnt, p + mcnt); + { + re_char *p1 = p; /* Next operation. */ + /* Here, we discard `const', making re_match non-reentrant. */ + unsigned char *p2 = (unsigned char*) p + mcnt; /* Jump dest. */ + unsigned char *p3 = (unsigned char*) p - 3; /* opcode location. */ + + p -= 3; /* Reset so that we will re-execute the + instruction once it's been changed. */ + + EXTRACT_NUMBER (mcnt, p2 - 2); + + /* Ensure this is a indeed the trivial kind of loop + we are expecting. */ + assert (skip_one_char (p1) == p2 - 3); + assert ((re_opcode_t) p2[-3] == jump && p2 + mcnt == p); + DEBUG_STATEMENT (debug += 2); + if (mutually_exclusive_p (bufp, p1, p2)) + { + /* Use a fast `on_failure_keep_string_jump' loop. */ + DEBUG_PRINT1 (" smart exclusive => fast loop.\n"); + *p3 = (unsigned char) on_failure_keep_string_jump; + STORE_NUMBER (p2 - 2, mcnt + 3); + } + else + { + /* Default to a safe `on_failure_jump' loop. */ + DEBUG_PRINT1 (" smart default => slow loop.\n"); + *p3 = (unsigned char) on_failure_jump; + } + DEBUG_STATEMENT (debug -= 2); + } + break; + + /* Unconditionally jump (without popping any failure points). */ + case jump: + unconditional_jump: + IMMEDIATE_QUIT_CHECK; + EXTRACT_NUMBER_AND_INCR (mcnt, p); /* Get the amount to jump. */ + DEBUG_PRINT2 ("EXECUTING jump %d ", mcnt); + p += mcnt; /* Do the jump. */ + DEBUG_PRINT2 ("(to %p).\n", p); + break; + + + /* Have to succeed matching what follows at least n times. + After that, handle like `on_failure_jump'. */ + case succeed_n: + /* Signedness doesn't matter since we only compare MCNT to 0. */ + EXTRACT_NUMBER (mcnt, p + 2); + DEBUG_PRINT2 ("EXECUTING succeed_n %d.\n", mcnt); + + /* Originally, mcnt is how many times we HAVE to succeed. */ + if (mcnt != 0) + { + /* Here, we discard `const', making re_match non-reentrant. */ + unsigned char *p2 = (unsigned char*) p + 2; /* counter loc. */ + mcnt--; + p += 4; + PUSH_NUMBER (p2, mcnt); + } + else + /* The two bytes encoding mcnt == 0 are two no_op opcodes. */ + goto on_failure; + break; + + case jump_n: + /* Signedness doesn't matter since we only compare MCNT to 0. */ + EXTRACT_NUMBER (mcnt, p + 2); + DEBUG_PRINT2 ("EXECUTING jump_n %d.\n", mcnt); + + /* Originally, this is how many times we CAN jump. */ + if (mcnt != 0) + { + /* Here, we discard `const', making re_match non-reentrant. */ + unsigned char *p2 = (unsigned char*) p + 2; /* counter loc. */ + mcnt--; + PUSH_NUMBER (p2, mcnt); + goto unconditional_jump; + } + /* If don't have to jump any more, skip over the rest of command. */ + else + p += 4; + break; + + case set_number_at: + { + unsigned char *p2; /* Location of the counter. */ + DEBUG_PRINT1 ("EXECUTING set_number_at.\n"); + + EXTRACT_NUMBER_AND_INCR (mcnt, p); + /* Here, we discard `const', making re_match non-reentrant. */ + p2 = (unsigned char*) p + mcnt; + /* Signedness doesn't matter since we only copy MCNT's bits . */ + EXTRACT_NUMBER_AND_INCR (mcnt, p); + DEBUG_PRINT3 (" Setting %p to %d.\n", p2, mcnt); + PUSH_NUMBER (p2, mcnt); + break; + } + + case wordbound: + case notwordbound: + not = (re_opcode_t) *(p - 1) == notwordbound; + DEBUG_PRINT2 ("EXECUTING %swordbound.\n", not?"not":""); + + /* We SUCCEED (or FAIL) in one of the following cases: */ + + /* Case 1: D is at the beginning or the end of string. */ + if (AT_STRINGS_BEG (d) || AT_STRINGS_END (d)) + not = !not; + else + { + /* C1 is the character before D, S1 is the syntax of C1, C2 + is the character at D, and S2 is the syntax of C2. */ + re_wchar_t c1, c2; + int s1, s2; +#ifdef emacs + int offset = PTR_TO_OFFSET (d - 1); + int charpos = SYNTAX_TABLE_BYTE_TO_CHAR (offset); + UPDATE_SYNTAX_TABLE (charpos); +#endif + GET_CHAR_BEFORE_2 (c1, d, string1, end1, string2, end2); + s1 = SYNTAX (c1); +#ifdef emacs + UPDATE_SYNTAX_TABLE_FORWARD (charpos + 1); +#endif + PREFETCH_NOLIMIT (); + c2 = RE_STRING_CHAR (d, dend - d); + s2 = SYNTAX (c2); + + if (/* Case 2: Only one of S1 and S2 is Sword. */ + ((s1 == Sword) != (s2 == Sword)) + /* Case 3: Both of S1 and S2 are Sword, and macro + WORD_BOUNDARY_P (C1, C2) returns nonzero. */ + || ((s1 == Sword) && WORD_BOUNDARY_P (c1, c2))) + not = !not; + } + if (not) + break; + else + goto fail; + + case wordbeg: + DEBUG_PRINT1 ("EXECUTING wordbeg.\n"); + + /* We FAIL in one of the following cases: */ + + /* Case 1: D is at the end of string. */ + if (AT_STRINGS_END (d)) + goto fail; + else + { + /* C1 is the character before D, S1 is the syntax of C1, C2 + is the character at D, and S2 is the syntax of C2. */ + re_wchar_t c1, c2; + int s1, s2; +#ifdef emacs + int offset = PTR_TO_OFFSET (d); + int charpos = SYNTAX_TABLE_BYTE_TO_CHAR (offset); + UPDATE_SYNTAX_TABLE (charpos); +#endif + PREFETCH (); + c2 = RE_STRING_CHAR (d, dend - d); + s2 = SYNTAX (c2); + + /* Case 2: S2 is not Sword. */ + if (s2 != Sword) + goto fail; + + /* Case 3: D is not at the beginning of string ... */ + if (!AT_STRINGS_BEG (d)) + { + GET_CHAR_BEFORE_2 (c1, d, string1, end1, string2, end2); +#ifdef emacs + UPDATE_SYNTAX_TABLE_BACKWARD (charpos - 1); +#endif + s1 = SYNTAX (c1); + + /* ... and S1 is Sword, and WORD_BOUNDARY_P (C1, C2) + returns 0. */ + if ((s1 == Sword) && !WORD_BOUNDARY_P (c1, c2)) + goto fail; + } + } + break; + + case wordend: + DEBUG_PRINT1 ("EXECUTING wordend.\n"); + + /* We FAIL in one of the following cases: */ + + /* Case 1: D is at the beginning of string. */ + if (AT_STRINGS_BEG (d)) + goto fail; + else + { + /* C1 is the character before D, S1 is the syntax of C1, C2 + is the character at D, and S2 is the syntax of C2. */ + re_wchar_t c1, c2; + int s1, s2; +#ifdef emacs + int offset = PTR_TO_OFFSET (d) - 1; + int charpos = SYNTAX_TABLE_BYTE_TO_CHAR (offset); + UPDATE_SYNTAX_TABLE (charpos); +#endif + GET_CHAR_BEFORE_2 (c1, d, string1, end1, string2, end2); + s1 = SYNTAX (c1); + + /* Case 2: S1 is not Sword. */ + if (s1 != Sword) + goto fail; + + /* Case 3: D is not at the end of string ... */ + if (!AT_STRINGS_END (d)) + { + PREFETCH_NOLIMIT (); + c2 = RE_STRING_CHAR (d, dend - d); +#ifdef emacs + UPDATE_SYNTAX_TABLE_FORWARD (charpos); +#endif + s2 = SYNTAX (c2); + + /* ... and S2 is Sword, and WORD_BOUNDARY_P (C1, C2) + returns 0. */ + if ((s2 == Sword) && !WORD_BOUNDARY_P (c1, c2)) + goto fail; + } + } + break; + + case syntaxspec: + case notsyntaxspec: + not = (re_opcode_t) *(p - 1) == notsyntaxspec; + mcnt = *p++; + DEBUG_PRINT3 ("EXECUTING %ssyntaxspec %d.\n", not?"not":"", mcnt); + PREFETCH (); +#ifdef emacs + { + int offset = PTR_TO_OFFSET (d); + int pos1 = SYNTAX_TABLE_BYTE_TO_CHAR (offset); + UPDATE_SYNTAX_TABLE (pos1); + } +#endif + { + int len; + re_wchar_t c; + + c = RE_STRING_CHAR_AND_LENGTH (d, dend - d, len); + + if ((SYNTAX (c) != (enum syntaxcode) mcnt) ^ not) + goto fail; + d += len; + } + break; + +#ifdef emacs + case before_dot: + DEBUG_PRINT1 ("EXECUTING before_dot.\n"); + if (PTR_BYTE_POS (d) >= PT_BYTE) + goto fail; + break; + + case at_dot: + DEBUG_PRINT1 ("EXECUTING at_dot.\n"); + if (PTR_BYTE_POS (d) != PT_BYTE) + goto fail; + break; + + case after_dot: + DEBUG_PRINT1 ("EXECUTING after_dot.\n"); + if (PTR_BYTE_POS (d) <= PT_BYTE) + goto fail; + break; + + case categoryspec: + case notcategoryspec: + not = (re_opcode_t) *(p - 1) == notcategoryspec; + mcnt = *p++; + DEBUG_PRINT3 ("EXECUTING %scategoryspec %d.\n", not?"not":"", mcnt); + PREFETCH (); + { + int len; + re_wchar_t c; + + c = RE_STRING_CHAR_AND_LENGTH (d, dend - d, len); + + if ((!CHAR_HAS_CATEGORY (c, mcnt)) ^ not) + goto fail; + d += len; + } + break; + +#endif /* emacs */ + + default: + abort (); + } + continue; /* Successfully executed one pattern command; keep going. */ + + + /* We goto here if a matching operation fails. */ + fail: + IMMEDIATE_QUIT_CHECK; + if (!FAIL_STACK_EMPTY ()) + { + re_char *str, *pat; + /* A restart point is known. Restore to that state. */ + DEBUG_PRINT1 ("\nFAIL:\n"); + POP_FAILURE_POINT (str, pat); + switch (SWITCH_ENUM_CAST ((re_opcode_t) *pat++)) + { + case on_failure_keep_string_jump: + assert (str == NULL); + goto continue_failure_jump; + + case on_failure_jump_nastyloop: + assert ((re_opcode_t)pat[-2] == no_op); + PUSH_FAILURE_POINT (pat - 2, str); + /* Fallthrough */ + + case on_failure_jump_loop: + case on_failure_jump: + case succeed_n: + d = str; + continue_failure_jump: + EXTRACT_NUMBER_AND_INCR (mcnt, pat); + p = pat + mcnt; + break; + + case no_op: + /* A special frame used for nastyloops. */ + goto fail; + + default: + abort(); + } + + assert (p >= bufp->buffer && p <= pend); + + if (d >= string1 && d <= end1) + dend = end_match_1; + } + else + break; /* Matching at this starting point really fails. */ + } /* for (;;) */ + + if (best_regs_set) + goto restore_best_regs; + + FREE_VARIABLES (); + + return -1; /* Failure to match. */ +} /* re_match_2 */ + +/* Subroutine definitions for re_match_2. */ + +/* Return zero if TRANSLATE[S1] and TRANSLATE[S2] are identical for LEN + bytes; nonzero otherwise. */ + +static int +bcmp_translate (s1, s2, len, translate, multibyte) + re_char *s1, *s2; + register int len; + RE_TRANSLATE_TYPE translate; + const int multibyte; +{ + register re_char *p1 = s1, *p2 = s2; + re_char *p1_end = s1 + len; + re_char *p2_end = s2 + len; + + /* FIXME: Checking both p1 and p2 presumes that the two strings might have + different lengths, but relying on a single `len' would break this. -sm */ + while (p1 < p1_end && p2 < p2_end) + { + int p1_charlen, p2_charlen; + re_wchar_t p1_ch, p2_ch; + + p1_ch = RE_STRING_CHAR_AND_LENGTH (p1, p1_end - p1, p1_charlen); + p2_ch = RE_STRING_CHAR_AND_LENGTH (p2, p2_end - p2, p2_charlen); + + if (RE_TRANSLATE (translate, p1_ch) + != RE_TRANSLATE (translate, p2_ch)) + return 1; + + p1 += p1_charlen, p2 += p2_charlen; + } + + if (p1 != p1_end || p2 != p2_end) + return 1; + + return 0; +} + +/* Entry points for GNU code. */ + +/* re_compile_pattern is the GNU regular expression compiler: it + compiles PATTERN (of length SIZE) and puts the result in BUFP. + Returns 0 if the pattern was valid, otherwise an error string. + + Assumes the `allocated' (and perhaps `buffer') and `translate' fields + are set in BUFP on entry. + + We call regex_compile to do the actual compilation. */ + +const char * +re_compile_pattern (pattern, length, bufp) + const char *pattern; + size_t length; + struct re_pattern_buffer *bufp; +{ + reg_errcode_t ret; + + /* GNU code is written to assume at least RE_NREGS registers will be set + (and at least one extra will be -1). */ + bufp->regs_allocated = REGS_UNALLOCATED; + + /* And GNU code determines whether or not to get register information + by passing null for the REGS argument to re_match, etc., not by + setting no_sub. */ + bufp->no_sub = 0; + + ret = regex_compile ((re_char*) pattern, length, re_syntax_options, bufp); + + if (!ret) + return NULL; + return gettext (re_error_msgid[(int) ret]); +} +WEAK_ALIAS (__re_compile_pattern, re_compile_pattern) + +/* Entry points compatible with 4.2 BSD regex library. We don't define + them unless specifically requested. */ + +#if defined _REGEX_RE_COMP || defined _LIBC + +/* BSD has one and only one pattern buffer. */ +static struct re_pattern_buffer re_comp_buf; + +char * +# ifdef _LIBC +/* Make these definitions weak in libc, so POSIX programs can redefine + these names if they don't use our functions, and still use + regcomp/regexec below without link errors. */ +weak_function +# endif +re_comp (s) + const char *s; +{ + reg_errcode_t ret; + + if (!s) + { + if (!re_comp_buf.buffer) + /* Yes, we're discarding `const' here if !HAVE_LIBINTL. */ + return (char *) gettext ("No previous regular expression"); + return 0; + } + + if (!re_comp_buf.buffer) + { + re_comp_buf.buffer = (unsigned char *) malloc (200); + if (re_comp_buf.buffer == NULL) + /* Yes, we're discarding `const' here if !HAVE_LIBINTL. */ + return (char *) gettext (re_error_msgid[(int) REG_ESPACE]); + re_comp_buf.allocated = 200; + + re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH); + if (re_comp_buf.fastmap == NULL) + /* Yes, we're discarding `const' here if !HAVE_LIBINTL. */ + return (char *) gettext (re_error_msgid[(int) REG_ESPACE]); + } + + /* Since `re_exec' always passes NULL for the `regs' argument, we + don't need to initialize the pattern buffer fields which affect it. */ + + ret = regex_compile (s, strlen (s), re_syntax_options, &re_comp_buf); + + if (!ret) + return NULL; + + /* Yes, we're discarding `const' here if !HAVE_LIBINTL. */ + return (char *) gettext (re_error_msgid[(int) ret]); +} + + +int +# ifdef _LIBC +weak_function +# endif +re_exec (s) + const char *s; +{ + const int len = strlen (s); + return + 0 <= re_search (&re_comp_buf, s, len, 0, len, (struct re_registers *) 0); +} +#endif /* _REGEX_RE_COMP */ + +/* POSIX.2 functions. Don't define these for Emacs. */ + +#ifndef emacs + +/* regcomp takes a regular expression as a string and compiles it. + + PREG is a regex_t *. We do not expect any fields to be initialized, + since POSIX says we shouldn't. Thus, we set + + `buffer' to the compiled pattern; + `used' to the length of the compiled pattern; + `syntax' to RE_SYNTAX_POSIX_EXTENDED if the + REG_EXTENDED bit in CFLAGS is set; otherwise, to + RE_SYNTAX_POSIX_BASIC; + `fastmap' to an allocated space for the fastmap; + `fastmap_accurate' to zero; + `re_nsub' to the number of subexpressions in PATTERN. + + PATTERN is the address of the pattern string. + + CFLAGS is a series of bits which affect compilation. + + If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we + use POSIX basic syntax. + + If REG_NEWLINE is set, then . and [^...] don't match newline. + Also, regexec will try a match beginning after every newline. + + If REG_ICASE is set, then we considers upper- and lowercase + versions of letters to be equivalent when matching. + + If REG_NOSUB is set, then when PREG is passed to regexec, that + routine will report only success or failure, and nothing about the + registers. + + It returns 0 if it succeeds, nonzero if it doesn't. (See regex.h for + the return codes and their meanings.) */ + +int +regcomp (preg, pattern, cflags) + regex_t *__restrict preg; + const char *__restrict pattern; + int cflags; +{ + reg_errcode_t ret; + reg_syntax_t syntax + = (cflags & REG_EXTENDED) ? + RE_SYNTAX_POSIX_EXTENDED : RE_SYNTAX_POSIX_BASIC; + + /* regex_compile will allocate the space for the compiled pattern. */ + preg->buffer = 0; + preg->allocated = 0; + preg->used = 0; + + /* Try to allocate space for the fastmap. */ + preg->fastmap = (char *) malloc (1 << BYTEWIDTH); + + if (cflags & REG_ICASE) + { + unsigned i; + + preg->translate + = (RE_TRANSLATE_TYPE) malloc (CHAR_SET_SIZE + * sizeof (*(RE_TRANSLATE_TYPE)0)); + if (preg->translate == NULL) + return (int) REG_ESPACE; + + /* Map uppercase characters to corresponding lowercase ones. */ + for (i = 0; i < CHAR_SET_SIZE; i++) + preg->translate[i] = ISUPPER (i) ? TOLOWER (i) : i; + } + else + preg->translate = NULL; + + /* If REG_NEWLINE is set, newlines are treated differently. */ + if (cflags & REG_NEWLINE) + { /* REG_NEWLINE implies neither . nor [^...] match newline. */ + syntax &= ~RE_DOT_NEWLINE; + syntax |= RE_HAT_LISTS_NOT_NEWLINE; + } + else + syntax |= RE_NO_NEWLINE_ANCHOR; + + preg->no_sub = !!(cflags & REG_NOSUB); + + /* POSIX says a null character in the pattern terminates it, so we + can use strlen here in compiling the pattern. */ + ret = regex_compile ((re_char*) pattern, strlen (pattern), syntax, preg); + + /* POSIX doesn't distinguish between an unmatched open-group and an + unmatched close-group: both are REG_EPAREN. */ + if (ret == REG_ERPAREN) + ret = REG_EPAREN; + + if (ret == REG_NOERROR && preg->fastmap) + { /* Compute the fastmap now, since regexec cannot modify the pattern + buffer. */ + re_compile_fastmap (preg); + if (preg->can_be_null) + { /* The fastmap can't be used anyway. */ + free (preg->fastmap); + preg->fastmap = NULL; + } + } + return (int) ret; +} +WEAK_ALIAS (__regcomp, regcomp) + + +/* regexec searches for a given pattern, specified by PREG, in the + string STRING. + + If NMATCH is zero or REG_NOSUB was set in the cflags argument to + `regcomp', we ignore PMATCH. Otherwise, we assume PMATCH has at + least NMATCH elements, and we set them to the offsets of the + corresponding matched substrings. + + EFLAGS specifies `execution flags' which affect matching: if + REG_NOTBOL is set, then ^ does not match at the beginning of the + string; if REG_NOTEOL is set, then $ does not match at the end. + + We return 0 if we find a match and REG_NOMATCH if not. */ + +int +regexec (preg, string, nmatch, pmatch, eflags) + const regex_t *__restrict preg; + const char *__restrict string; + size_t nmatch; + regmatch_t pmatch[__restrict_arr]; + int eflags; +{ + int ret; + struct re_registers regs; + regex_t private_preg; + int len = strlen (string); + boolean want_reg_info = !preg->no_sub && nmatch > 0 && pmatch; + + private_preg = *preg; + + private_preg.not_bol = !!(eflags & REG_NOTBOL); + private_preg.not_eol = !!(eflags & REG_NOTEOL); + + /* The user has told us exactly how many registers to return + information about, via `nmatch'. We have to pass that on to the + matching routines. */ + private_preg.regs_allocated = REGS_FIXED; + + if (want_reg_info) + { + regs.num_regs = nmatch; + regs.start = TALLOC (nmatch * 2, regoff_t); + if (regs.start == NULL) + return (int) REG_NOMATCH; + regs.end = regs.start + nmatch; + } + + /* Instead of using not_eol to implement REG_NOTEOL, we could simply + pass (&private_preg, string, len + 1, 0, len, ...) pretending the string + was a little bit longer but still only matching the real part. + This works because the `endline' will check for a '\n' and will find a + '\0', correctly deciding that this is not the end of a line. + But it doesn't work out so nicely for REG_NOTBOL, since we don't have + a convenient '\0' there. For all we know, the string could be preceded + by '\n' which would throw things off. */ + + /* Perform the searching operation. */ + ret = re_search (&private_preg, string, len, + /* start: */ 0, /* range: */ len, + want_reg_info ? ®s : (struct re_registers *) 0); + + /* Copy the register information to the POSIX structure. */ + if (want_reg_info) + { + if (ret >= 0) + { + unsigned r; + + for (r = 0; r < nmatch; r++) + { + pmatch[r].rm_so = regs.start[r]; + pmatch[r].rm_eo = regs.end[r]; + } + } + + /* If we needed the temporary register info, free the space now. */ + free (regs.start); + } + + /* We want zero return to mean success, unlike `re_search'. */ + return ret >= 0 ? (int) REG_NOERROR : (int) REG_NOMATCH; +} +WEAK_ALIAS (__regexec, regexec) + + +/* Returns a message corresponding to an error code, ERRCODE, returned + from either regcomp or regexec. We don't use PREG here. */ + +size_t +regerror (errcode, preg, errbuf, errbuf_size) + int errcode; + const regex_t *preg; + char *errbuf; + size_t errbuf_size; +{ + const char *msg; + size_t msg_size; + + if (errcode < 0 + || errcode >= (sizeof (re_error_msgid) / sizeof (re_error_msgid[0]))) + /* Only error codes returned by the rest of the code should be passed + to this routine. If we are given anything else, or if other regex + code generates an invalid error code, then the program has a bug. + Dump core so we can fix it. */ + abort (); + + msg = gettext (re_error_msgid[errcode]); + + msg_size = strlen (msg) + 1; /* Includes the null. */ + + if (errbuf_size != 0) + { + if (msg_size > errbuf_size) + { + strncpy (errbuf, msg, errbuf_size - 1); + errbuf[errbuf_size - 1] = 0; + } + else + strcpy (errbuf, msg); + } + + return msg_size; +} +WEAK_ALIAS (__regerror, regerror) + + +/* Free dynamically allocated space used by PREG. */ + +void +regfree (preg) + regex_t *preg; +{ + if (preg->buffer != NULL) + free (preg->buffer); + preg->buffer = NULL; + + preg->allocated = 0; + preg->used = 0; + + if (preg->fastmap != NULL) + free (preg->fastmap); + preg->fastmap = NULL; + preg->fastmap_accurate = 0; + + if (preg->translate != NULL) + free (preg->translate); + preg->translate = NULL; +} +WEAK_ALIAS (__regfree, regfree) + +#endif /* not emacs */ + +/* arch-tag: 4ffd68ba-2a9e-435b-a21a-018990f9eeb2 + (do not change this comment) */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/regex.h Sun Dec 28 16:05:28 2003 +0000 @@ -0,0 +1,576 @@ +/* Definitions for data structures and routines for the regular + expression library, version 0.12. + + Copyright (C) 1985,89,90,91,92,93,95,2000 Free Software Foundation, Inc. + + This program 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. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifndef _REGEX_H +#define _REGEX_H 1 + +/* Allow the use in C++ code. */ +#ifdef __cplusplus +extern "C" { +#endif + +/* POSIX says that <sys/types.h> must be included (by the caller) before + <regex.h>. */ + +#if !defined _POSIX_C_SOURCE && !defined _POSIX_SOURCE && defined VMS +/* VMS doesn't have `size_t' in <sys/types.h>, even though POSIX says it + should be there. */ +# include <stddef.h> +#endif + +/* The following bits are used to determine the regexp syntax we + recognize. The set/not-set meanings where historically chosen so + that Emacs syntax had the value 0. + The bits are given in alphabetical order, and + the definitions shifted by one from the previous bit; thus, when we + add or remove a bit, only one other definition need change. */ +typedef unsigned long int reg_syntax_t; + +/* If this bit is not set, then \ inside a bracket expression is literal. + If set, then such a \ quotes the following character. */ +#define RE_BACKSLASH_ESCAPE_IN_LISTS ((unsigned long int) 1) + +/* If this bit is not set, then + and ? are operators, and \+ and \? are + literals. + If set, then \+ and \? are operators and + and ? are literals. */ +#define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1) + +/* If this bit is set, then character classes are supported. They are: + [:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:], + [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:]. + If not set, then character classes are not supported. */ +#define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1) + +/* If this bit is set, then ^ and $ are always anchors (outside bracket + expressions, of course). + If this bit is not set, then it depends: + ^ is an anchor if it is at the beginning of a regular + expression or after an open-group or an alternation operator; + $ is an anchor if it is at the end of a regular expression, or + before a close-group or an alternation operator. + + This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because + POSIX draft 11.2 says that * etc. in leading positions is undefined. + We already implemented a previous draft which made those constructs + invalid, though, so we haven't changed the code back. */ +#define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1) + +/* If this bit is set, then special characters are always special + regardless of where they are in the pattern. + If this bit is not set, then special characters are special only in + some contexts; otherwise they are ordinary. Specifically, + * + ? and intervals are only special when not after the beginning, + open-group, or alternation operator. */ +#define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1) + +/* If this bit is set, then *, +, ?, and { cannot be first in an re or + immediately after an alternation or begin-group operator. */ +#define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1) + +/* If this bit is set, then . matches newline. + If not set, then it doesn't. */ +#define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1) + +/* If this bit is set, then . doesn't match NUL. + If not set, then it does. */ +#define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1) + +/* If this bit is set, nonmatching lists [^...] do not match newline. + If not set, they do. */ +#define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1) + +/* If this bit is set, either \{...\} or {...} defines an + interval, depending on RE_NO_BK_BRACES. + If not set, \{, \}, {, and } are literals. */ +#define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1) + +/* If this bit is set, +, ? and | aren't recognized as operators. + If not set, they are. */ +#define RE_LIMITED_OPS (RE_INTERVALS << 1) + +/* If this bit is set, newline is an alternation operator. + If not set, newline is literal. */ +#define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1) + +/* If this bit is set, then `{...}' defines an interval, and \{ and \} + are literals. + If not set, then `\{...\}' defines an interval. */ +#define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1) + +/* If this bit is set, (...) defines a group, and \( and \) are literals. + If not set, \(...\) defines a group, and ( and ) are literals. */ +#define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1) + +/* If this bit is set, then \<digit> matches <digit>. + If not set, then \<digit> is a back-reference. */ +#define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1) + +/* If this bit is set, then | is an alternation operator, and \| is literal. + If not set, then \| is an alternation operator, and | is literal. */ +#define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1) + +/* If this bit is set, then an ending range point collating higher + than the starting range point, as in [z-a], is invalid. + If not set, then when ending range point collates higher than the + starting range point, the range is ignored. */ +#define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1) + +/* If this bit is set, then an unmatched ) is ordinary. + If not set, then an unmatched ) is invalid. */ +#define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1) + +/* If this bit is set, succeed as soon as we match the whole pattern, + without further backtracking. */ +#define RE_NO_POSIX_BACKTRACKING (RE_UNMATCHED_RIGHT_PAREN_ORD << 1) + +/* If this bit is set, do not process the GNU regex operators. + If not set, then the GNU regex operators are recognized. */ +#define RE_NO_GNU_OPS (RE_NO_POSIX_BACKTRACKING << 1) + +/* If this bit is set, then *?, +? and ?? match non greedily. */ +#define RE_FRUGAL (RE_NO_GNU_OPS << 1) + +/* If this bit is set, then (?:...) is treated as a shy group. */ +#define RE_SHY_GROUPS (RE_FRUGAL << 1) + +/* If this bit is set, ^ and $ only match at beg/end of buffer. */ +#define RE_NO_NEWLINE_ANCHOR (RE_SHY_GROUPS << 1) + +/* If this bit is set, turn on internal regex debugging. + If not set, and debugging was on, turn it off. + This only works if regex.c is compiled -DDEBUG. + We define this bit always, so that all that's needed to turn on + debugging is to recompile regex.c; the calling code can always have + this bit set, and it won't affect anything in the normal case. */ +#define RE_DEBUG (RE_NO_NEWLINE_ANCHOR << 1) + +/* This global variable defines the particular regexp syntax to use (for + some interfaces). When a regexp is compiled, the syntax used is + stored in the pattern buffer, so changing this does not affect + already-compiled regexps. */ +extern reg_syntax_t re_syntax_options; + +#ifdef emacs +/* In Emacs, this is the string or buffer in which we + are matching. It is used for looking up syntax properties. */ +extern Lisp_Object re_match_object; +#endif + + +/* Define combinations of the above bits for the standard possibilities. + (The [[[ comments delimit what gets put into the Texinfo file, so + don't delete them!) */ +/* [[[begin syntaxes]]] */ +#define RE_SYNTAX_EMACS \ + (RE_CHAR_CLASSES | RE_INTERVALS | RE_SHY_GROUPS | RE_FRUGAL) + +#define RE_SYNTAX_AWK \ + (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \ + | RE_NO_BK_PARENS | RE_NO_BK_REFS \ + | RE_NO_BK_VBAR | RE_NO_EMPTY_RANGES \ + | RE_DOT_NEWLINE | RE_CONTEXT_INDEP_ANCHORS \ + | RE_UNMATCHED_RIGHT_PAREN_ORD | RE_NO_GNU_OPS) + +#define RE_SYNTAX_GNU_AWK \ + ((RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DEBUG) \ + & ~(RE_DOT_NOT_NULL | RE_INTERVALS | RE_CONTEXT_INDEP_OPS)) + +#define RE_SYNTAX_POSIX_AWK \ + (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS \ + | RE_INTERVALS | RE_NO_GNU_OPS) + +#define RE_SYNTAX_GREP \ + (RE_BK_PLUS_QM | RE_CHAR_CLASSES \ + | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS \ + | RE_NEWLINE_ALT) + +#define RE_SYNTAX_EGREP \ + (RE_CHAR_CLASSES | RE_CONTEXT_INDEP_ANCHORS \ + | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE \ + | RE_NEWLINE_ALT | RE_NO_BK_PARENS \ + | RE_NO_BK_VBAR) + +#define RE_SYNTAX_POSIX_EGREP \ + (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES) + +/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */ +#define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC + +#define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC + +/* Syntax bits common to both basic and extended POSIX regex syntax. */ +#define _RE_SYNTAX_POSIX_COMMON \ + (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \ + | RE_INTERVALS | RE_NO_EMPTY_RANGES) + +#define RE_SYNTAX_POSIX_BASIC \ + (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM) + +/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes + RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this + isn't minimal, since other operators, such as \`, aren't disabled. */ +#define RE_SYNTAX_POSIX_MINIMAL_BASIC \ + (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS) + +#define RE_SYNTAX_POSIX_EXTENDED \ + (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ + | RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \ + | RE_NO_BK_PARENS | RE_NO_BK_VBAR \ + | RE_CONTEXT_INVALID_OPS | RE_UNMATCHED_RIGHT_PAREN_ORD) + +/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INDEP_OPS is + removed and RE_NO_BK_REFS is added. */ +#define RE_SYNTAX_POSIX_MINIMAL_EXTENDED \ + (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ + | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \ + | RE_NO_BK_PARENS | RE_NO_BK_REFS \ + | RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD) +/* [[[end syntaxes]]] */ + +/* Maximum number of duplicates an interval can allow. Some systems + (erroneously) define this in other header files, but we want our + value, so remove any previous define. */ +#ifdef RE_DUP_MAX +# undef RE_DUP_MAX +#endif +/* If sizeof(int) == 2, then ((1 << 15) - 1) overflows. */ +#define RE_DUP_MAX (0x7fff) + + +/* POSIX `cflags' bits (i.e., information for `regcomp'). */ + +/* If this bit is set, then use extended regular expression syntax. + If not set, then use basic regular expression syntax. */ +#define REG_EXTENDED 1 + +/* If this bit is set, then ignore case when matching. + If not set, then case is significant. */ +#define REG_ICASE (REG_EXTENDED << 1) + +/* If this bit is set, then anchors do not match at newline + characters in the string. + If not set, then anchors do match at newlines. */ +#define REG_NEWLINE (REG_ICASE << 1) + +/* If this bit is set, then report only success or fail in regexec. + If not set, then returns differ between not matching and errors. */ +#define REG_NOSUB (REG_NEWLINE << 1) + + +/* POSIX `eflags' bits (i.e., information for regexec). */ + +/* If this bit is set, then the beginning-of-line operator doesn't match + the beginning of the string (presumably because it's not the + beginning of a line). + If not set, then the beginning-of-line operator does match the + beginning of the string. */ +#define REG_NOTBOL 1 + +/* Like REG_NOTBOL, except for the end-of-line. */ +#define REG_NOTEOL (1 << 1) + + +/* If any error codes are removed, changed, or added, update the + `re_error_msg' table in regex.c. */ +typedef enum +{ +#ifdef _XOPEN_SOURCE + REG_ENOSYS = -1, /* This will never happen for this implementation. */ +#endif + + REG_NOERROR = 0, /* Success. */ + REG_NOMATCH, /* Didn't find a match (for regexec). */ + + /* POSIX regcomp return error codes. (In the order listed in the + standard.) */ + REG_BADPAT, /* Invalid pattern. */ + REG_ECOLLATE, /* Not implemented. */ + REG_ECTYPE, /* Invalid character class name. */ + REG_EESCAPE, /* Trailing backslash. */ + REG_ESUBREG, /* Invalid back reference. */ + REG_EBRACK, /* Unmatched left bracket. */ + REG_EPAREN, /* Parenthesis imbalance. */ + REG_EBRACE, /* Unmatched \{. */ + REG_BADBR, /* Invalid contents of \{\}. */ + REG_ERANGE, /* Invalid range end. */ + REG_ESPACE, /* Ran out of memory. */ + REG_BADRPT, /* No preceding re for repetition op. */ + + /* Error codes we've added. */ + REG_EEND, /* Premature end. */ + REG_ESIZE, /* Compiled pattern bigger than 2^16 bytes. */ + REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */ +} reg_errcode_t; + +/* This data structure represents a compiled pattern. Before calling + the pattern compiler, the fields `buffer', `allocated', `fastmap', + `translate', and `no_sub' can be set. After the pattern has been + compiled, the `re_nsub' field is available. All other fields are + private to the regex routines. */ + +#ifndef RE_TRANSLATE_TYPE +# define RE_TRANSLATE_TYPE char * +#endif + +struct re_pattern_buffer +{ +/* [[[begin pattern_buffer]]] */ + /* Space that holds the compiled pattern. It is declared as + `unsigned char *' because its elements are + sometimes used as array indexes. */ + unsigned char *buffer; + + /* Number of bytes to which `buffer' points. */ + size_t allocated; + + /* Number of bytes actually used in `buffer'. */ + size_t used; + + /* Syntax setting with which the pattern was compiled. */ + reg_syntax_t syntax; + + /* Pointer to a fastmap, if any, otherwise zero. re_search uses + the fastmap, if there is one, to skip over impossible + starting points for matches. */ + char *fastmap; + + /* Either a translate table to apply to all characters before + comparing them, or zero for no translation. The translation + is applied to a pattern when it is compiled and to a string + when it is matched. */ + RE_TRANSLATE_TYPE translate; + + /* Number of subexpressions found by the compiler. */ + size_t re_nsub; + + /* Zero if this pattern cannot match the empty string, one else. + Well, in truth it's used only in `re_search_2', to see + whether or not we should use the fastmap, so we don't set + this absolutely perfectly; see `re_compile_fastmap'. */ + unsigned can_be_null : 1; + + /* If REGS_UNALLOCATED, allocate space in the `regs' structure + for `max (RE_NREGS, re_nsub + 1)' groups. + If REGS_REALLOCATE, reallocate space if necessary. + If REGS_FIXED, use what's there. */ +#define REGS_UNALLOCATED 0 +#define REGS_REALLOCATE 1 +#define REGS_FIXED 2 + unsigned regs_allocated : 2; + + /* Set to zero when `regex_compile' compiles a pattern; set to one + by `re_compile_fastmap' if it updates the fastmap. */ + unsigned fastmap_accurate : 1; + + /* If set, `re_match_2' does not return information about + subexpressions. */ + unsigned no_sub : 1; + + /* If set, a beginning-of-line anchor doesn't match at the + beginning of the string. */ + unsigned not_bol : 1; + + /* Similarly for an end-of-line anchor. */ + unsigned not_eol : 1; + +#ifdef emacs + /* If true, multi-byte form in the `buffer' should be recognized as a + multibyte character. */ + unsigned multibyte : 1; +#endif + +/* [[[end pattern_buffer]]] */ +}; + +typedef struct re_pattern_buffer regex_t; + +/* Type for byte offsets within the string. POSIX mandates this. */ +typedef int regoff_t; + + +/* This is the structure we store register match data in. See + regex.texinfo for a full description of what registers match. */ +struct re_registers +{ + unsigned num_regs; + regoff_t *start; + regoff_t *end; +}; + + +/* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer, + `re_match_2' returns information about at least this many registers + the first time a `regs' structure is passed. */ +#ifndef RE_NREGS +# define RE_NREGS 30 +#endif + + +/* POSIX specification for registers. Aside from the different names than + `re_registers', POSIX uses an array of structures, instead of a + structure of arrays. */ +typedef struct +{ + regoff_t rm_so; /* Byte offset from string's start to substring's start. */ + regoff_t rm_eo; /* Byte offset from string's start to substring's end. */ +} regmatch_t; + +/* Declarations for routines. */ + +/* To avoid duplicating every routine declaration -- once with a + prototype (if we are ANSI), and once without (if we aren't) -- we + use the following macro to declare argument types. This + unfortunately clutters up the declarations a bit, but I think it's + worth it. */ + +#if defined __STDC__ || defined PROTOTYPES + +# define _RE_ARGS(args) args + +#else /* not __STDC__ || PROTOTYPES */ + +# define _RE_ARGS(args) () + +#endif /* not __STDC__ || PROTOTYPES */ + +/* Sets the current default syntax to SYNTAX, and return the old syntax. + You can also simply assign to the `re_syntax_options' variable. */ +extern reg_syntax_t re_set_syntax _RE_ARGS ((reg_syntax_t syntax)); + +/* Compile the regular expression PATTERN, with length LENGTH + and syntax given by the global `re_syntax_options', into the buffer + BUFFER. Return NULL if successful, and an error string if not. */ +extern const char *re_compile_pattern + _RE_ARGS ((const char *pattern, size_t length, + struct re_pattern_buffer *buffer)); + + +/* Compile a fastmap for the compiled pattern in BUFFER; used to + accelerate searches. Return 0 if successful and -2 if was an + internal error. */ +extern int re_compile_fastmap _RE_ARGS ((struct re_pattern_buffer *buffer)); + + +/* Search in the string STRING (with length LENGTH) for the pattern + compiled into BUFFER. Start searching at position START, for RANGE + characters. Return the starting position of the match, -1 for no + match, or -2 for an internal error. Also return register + information in REGS (if REGS and BUFFER->no_sub are nonzero). */ +extern int re_search + _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string, + int length, int start, int range, struct re_registers *regs)); + + +/* Like `re_search', but search in the concatenation of STRING1 and + STRING2. Also, stop searching at index START + STOP. */ +extern int re_search_2 + _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1, + int length1, const char *string2, int length2, + int start, int range, struct re_registers *regs, int stop)); + + +/* Like `re_search', but return how many characters in STRING the regexp + in BUFFER matched, starting at position START. */ +extern int re_match + _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string, + int length, int start, struct re_registers *regs)); + + +/* Relates to `re_match' as `re_search_2' relates to `re_search'. */ +extern int re_match_2 + _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1, + int length1, const char *string2, int length2, + int start, struct re_registers *regs, int stop)); + + +/* Set REGS to hold NUM_REGS registers, storing them in STARTS and + ENDS. Subsequent matches using BUFFER and REGS will use this memory + for recording register information. STARTS and ENDS must be + allocated with malloc, and must each be at least `NUM_REGS * sizeof + (regoff_t)' bytes long. + + If NUM_REGS == 0, then subsequent matches should allocate their own + register data. + + Unless this function is called, the first search or match using + PATTERN_BUFFER will allocate its own register data, without + freeing the old data. */ +extern void re_set_registers + _RE_ARGS ((struct re_pattern_buffer *buffer, struct re_registers *regs, + unsigned num_regs, regoff_t *starts, regoff_t *ends)); + +#if defined _REGEX_RE_COMP || defined _LIBC +# ifndef _CRAY +/* 4.2 bsd compatibility. */ +extern char *re_comp _RE_ARGS ((const char *)); +extern int re_exec _RE_ARGS ((const char *)); +# endif +#endif + +/* GCC 2.95 and later have "__restrict"; C99 compilers have + "restrict", and "configure" may have defined "restrict". */ +#ifndef __restrict +# if ! (2 < __GNUC__ || (2 == __GNUC__ && 95 <= __GNUC_MINOR__)) +# if defined restrict || 199901L <= __STDC_VERSION__ +# define __restrict restrict +# else +# define __restrict +# endif +# endif +#endif +/* For now conditionally define __restrict_arr to expand to nothing. + Ideally we would have a test for the compiler which allows defining + it to restrict. */ +#ifndef __restrict_arr +# define __restrict_arr +#endif + +/* POSIX compatibility. */ +extern int regcomp _RE_ARGS ((regex_t *__restrict __preg, + const char *__restrict __pattern, + int __cflags)); + +extern int regexec _RE_ARGS ((const regex_t *__restrict __preg, + const char *__restrict __string, size_t __nmatch, + regmatch_t __pmatch[__restrict_arr], + int __eflags)); + +extern size_t regerror _RE_ARGS ((int __errcode, const regex_t *__preg, + char *__errbuf, size_t __errbuf_size)); + +extern void regfree _RE_ARGS ((regex_t *__preg)); + + +#ifdef __cplusplus +} +#endif /* C++ */ + +#endif /* regex.h */ + +/* +Local variables: +make-backup-files: t +version-control: t +trim-versions-without-asking: nil +End: +*/ + +/* arch-tag: bda6e3ec-3c02-4237-a55a-01ad2e120083 + (do not change this comment) */
--- a/src/termcap.c Sun Dec 28 16:04:37 2003 +0000 +++ b/src/termcap.c Sun Dec 28 16:05:28 2003 +0000 @@ -284,6 +284,52 @@ } *r++ = c; } + + /* Sometimes entries have "%pN" which means use parameter N in the + next %-substitution. If all such N are continuous in the range + [1,9] we can remove each "%pN" because they are redundant, thus + reducing bandwidth requirements. True, Emacs is well beyond the + days of 150baud teletypes, but some of its users aren't much so. + + This pass could probably be integrated into the one above but + abbreviation expansion makes that effort a little more hairy than + its worth; this is cleaner. */ + { + register int last_p_param = 0; + int remove_p_params = 1; + struct { char *beg; int len; } cut[11]; + + for (cut[0].beg = p = ret; p < r - 3; p++) + { + if (!remove_p_params) + break; + if (*p == '%' && *(p + 1) == 'p') + { + if (*(p + 2) - '0' == 1 + last_p_param) + { + cut[last_p_param].len = p - cut[last_p_param].beg; + last_p_param++; + p += 3; + cut[last_p_param].beg = p; + } + else /* not continuous: bail */ + remove_p_params = 0; + if (last_p_param > 10) /* too many: bail */ + remove_p_params = 0; + } + } + if (remove_p_params && last_p_param) + { + register int i; + char *wp; + + cut[last_p_param].len = r - cut[last_p_param].beg; + for (i = 0, wp = ret; i <= last_p_param; wp += cut[i++].len) + bcopy (cut[i].beg, wp, cut[i].len); + r = wp; + } + } + *r = '\0'; /* Update *AREA. */ if (area)
--- a/src/w32fns.c Sun Dec 28 16:04:37 2003 +0000 +++ b/src/w32fns.c Sun Dec 28 16:05:28 2003 +0000 @@ -6937,11 +6937,6 @@ static struct image_type *image_types; -/* The symbol `image' which is the car of the lists used to represent - images in Lisp. */ - -extern Lisp_Object Qimage; - /* The symbol `xbm' which is used as the type symbol for XBM images. */ Lisp_Object Qxbm; @@ -7021,7 +7016,7 @@ { int valid_p = 0; - if (CONSP (object) && EQ (XCAR (object), Qimage)) + if (IMAGEP (object)) { Lisp_Object tem; @@ -7123,7 +7118,7 @@ int i; Lisp_Object plist; - if (!CONSP (spec) || !EQ (XCAR (spec), Qimage)) + if (!IMAGEP (spec)) return 0; plist = XCDR (spec);
--- a/src/w32menu.c Sun Dec 28 16:04:37 2003 +0000 +++ b/src/w32menu.c Sun Dec 28 16:05:28 2003 +0000 @@ -153,7 +153,6 @@ Lisp_Object Qdebug_on_next_call; extern Lisp_Object Qmenu_bar; -extern Lisp_Object Qmouse_click, Qevent_kind; extern Lisp_Object QCtoggle, QCradio;
--- a/src/w32term.c Sun Dec 28 16:04:37 2003 +0000 +++ b/src/w32term.c Sun Dec 28 16:05:28 2003 +0000 @@ -221,8 +221,6 @@ extern Lisp_Object Vcommand_line_args, Vsystem_name; -extern Lisp_Object Qface, Qmouse_face; - #ifndef USE_CRT_DLL extern int errno; #endif
--- a/src/xdisp.c Sun Dec 28 16:04:37 2003 +0000 +++ b/src/xdisp.c Sun Dec 28 16:05:28 2003 +0000 @@ -243,6 +243,9 @@ /* Cursor shapes */ Lisp_Object Qbar, Qhbar, Qbox, Qhollow; +/* Pointer shapes */ +Lisp_Object Qarrow, Qhand, Qtext; + Lisp_Object Qrisky_local_variable; /* Holds the list (error). */ @@ -291,7 +294,7 @@ /* Names of text properties relevant for redisplay. */ -Lisp_Object Qdisplay, Qrelative_width, Qalign_to; +Lisp_Object Qdisplay; extern Lisp_Object Qface, Qinvisible, Qwidth; /* Symbols used in text property values. */ @@ -299,7 +302,7 @@ Lisp_Object Vdisplay_pixels_per_inch; Lisp_Object Qspace, QCalign_to, QCrelative_width, QCrelative_height; Lisp_Object Qleft_margin, Qright_margin, Qspace_width, Qraise; -Lisp_Object Qmargin; +Lisp_Object Qmargin, Qpointer; extern Lisp_Object Qheight; extern Lisp_Object QCwidth, QCheight, QCascent; extern Lisp_Object Qscroll_bar; @@ -312,7 +315,7 @@ i.e. in blank areas after eol and eob. This used to be the default in 21.3. */ -Lisp_Object Vshow_text_cursor_in_void; +Lisp_Object Vvoid_text_area_pointer; /* Name of the face used to highlight trailing whitespace. */ @@ -323,6 +326,10 @@ Lisp_Object Qimage; +/* The image map types. */ +Lisp_Object QCmap, QCpointer; +Lisp_Object Qrect, Qcircle, Qpoly; + /* Non-zero means print newline to stdout before next mini-buffer message. */ @@ -1579,11 +1586,10 @@ date. */ static struct glyph * -x_y_to_hpos_vpos (w, x, y, hpos, vpos, area, buffer_only_p) +x_y_to_hpos_vpos (w, x, y, hpos, vpos, dx, dy, area) struct window *w; int x, y; - int *hpos, *vpos, *area; - int buffer_only_p; + int *hpos, *vpos, *dx, *dy, *area; { struct glyph *glyph, *end; struct glyph_row *row = NULL; @@ -1634,23 +1640,22 @@ /* Find glyph containing X. */ glyph = row->glyphs[*area]; end = glyph + row->used[*area]; - while (glyph < end) - { - if (x < x0 + glyph->pixel_width) - { - if (w->pseudo_window_p) - break; - else if (!buffer_only_p || BUFFERP (glyph->object)) - break; - } - - x0 += glyph->pixel_width; + x -= x0; + while (glyph < end && x >= glyph->pixel_width) + { + x -= glyph->pixel_width; ++glyph; } if (glyph == end) return NULL; + if (dx) + { + *dx = x; + *dy = y - (row->y + row->ascent - glyph->ascent); + } + *hpos = glyph - row->glyphs[*area]; return glyph; } @@ -1738,20 +1743,28 @@ r.y = WINDOW_TO_FRAME_PIXEL_Y (s->w, r.y); -#ifdef HAVE_NTGUI - /* ++KFS: From W32 port, but it looks ok for all platforms to me. */ /* If drawing the cursor, don't let glyph draw outside its advertised boundaries. Cleartype does this under some circumstances. */ if (s->hl == DRAW_CURSOR) { + struct glyph *glyph = s->first_glyph; + int height; + if (s->x > r.x) { r.width -= s->x - r.x; r.x = s->x; } - r.width = min (r.width, s->first_glyph->pixel_width); - } -#endif + r.width = min (r.width, glyph->pixel_width); + + /* Don't draw cursor glyph taller than our actual glyph. */ + height = max (FRAME_LINE_HEIGHT (s->f), glyph->ascent + glyph->descent); + if (height < r.height) + { + r.y = s->ybase + glyph->descent - height; + r.height = height; + } + } #ifdef CONVERT_FROM_XRECT CONVERT_FROM_XRECT (r, *nr); @@ -8276,7 +8289,7 @@ int enabled_p = !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P)); int selected_p = !NILP (PROP (TOOL_BAR_ITEM_SELECTED_P)); int hmargin, vmargin, relief, idx, end; - extern Lisp_Object QCrelief, QCmargin, QCconversion, Qimage; + extern Lisp_Object QCrelief, QCmargin, QCconversion; /* If image is a vector, choose the image according to the button state. */ @@ -8693,7 +8706,7 @@ int area; /* Find the glyph under X/Y. */ - *glyph = x_y_to_hpos_vpos (w, x, y, hpos, vpos, &area, 0); + *glyph = x_y_to_hpos_vpos (w, x, y, hpos, vpos, 0, 0, &area); if (*glyph == NULL) return -1; @@ -17682,6 +17695,8 @@ glyph->charpos = CHARPOS (it->position); glyph->object = it->object; glyph->pixel_width = it->pixel_width; + glyph->ascent = it->ascent; + glyph->descent = it->descent; glyph->voffset = it->voffset; glyph->type = CHAR_GLYPH; glyph->multibyte_p = it->multibyte_p; @@ -17716,6 +17731,8 @@ glyph->charpos = CHARPOS (it->position); glyph->object = it->object; glyph->pixel_width = it->pixel_width; + glyph->ascent = it->ascent; + glyph->descent = it->descent; glyph->voffset = it->voffset; glyph->type = COMPOSITE_GLYPH; glyph->multibyte_p = it->multibyte_p; @@ -17764,6 +17781,7 @@ { struct image *img; struct face *face; + int face_ascent, glyph_ascent; xassert (it->what == IT_IMAGE); @@ -17775,10 +17793,15 @@ PREPARE_FACE_FOR_DISPLAY (it->f, face); prepare_image_for_display (it->f, img); - it->ascent = it->phys_ascent = image_ascent (img, face); + it->ascent = it->phys_ascent = glyph_ascent = image_ascent (img, face); it->descent = it->phys_descent = img->height + 2 * img->vmargin - it->ascent; it->pixel_width = img->width + 2 * img->hmargin; + /* If this glyph is alone on the last line, adjust it.ascent to minimum row ascent. */ + face_ascent = face->font ? FONT_BASE (face->font) : FRAME_BASELINE_OFFSET (it->f); + if (face_ascent > it->ascent) + it->ascent = it->phys_ascent = face_ascent; + it->nglyphs = 1; if (face->box != FACE_NO_BOX) @@ -17808,6 +17831,8 @@ glyph->charpos = CHARPOS (it->position); glyph->object = it->object; glyph->pixel_width = it->pixel_width; + glyph->ascent = glyph_ascent; + glyph->descent = it->descent; glyph->voffset = it->voffset; glyph->type = IMAGE_GLYPH; glyph->multibyte_p = it->multibyte_p; @@ -17847,6 +17872,8 @@ glyph->charpos = CHARPOS (it->position); glyph->object = object; glyph->pixel_width = width; + glyph->ascent = ascent; + glyph->descent = height - ascent; glyph->voffset = it->voffset; glyph->type = STRETCH_GLYPH; glyph->multibyte_p = it->multibyte_p; @@ -19942,6 +19969,189 @@ } +/* See if position X, Y is within a hot-spot of an image. */ + +static int +on_hot_spot_p (hot_spot, x, y) + Lisp_Object hot_spot; + int x, y; +{ + if (!CONSP (hot_spot)) + return 0; + + if (EQ (XCAR (hot_spot), Qrect)) + { + /* CDR is (Top-Left . Bottom-Right) = ((x0 . y0) . (x1 . y1)) */ + Lisp_Object rect = XCDR (hot_spot); + Lisp_Object tem; + if (!CONSP (rect)) + return 0; + if (!CONSP (XCAR (rect))) + return 0; + if (!CONSP (XCDR (rect))) + return 0; + if (!(tem = XCAR (XCAR (rect)), INTEGERP (tem) && x >= XINT (tem))) + return 0; + if (!(tem = XCDR (XCAR (rect)), INTEGERP (tem) && y >= XINT (tem))) + return 0; + if (!(tem = XCAR (XCDR (rect)), INTEGERP (tem) && x <= XINT (tem))) + return 0; + if (!(tem = XCDR (XCDR (rect)), INTEGERP (tem) && y <= XINT (tem))) + return 0; + return 1; + } + else if (EQ (XCAR (hot_spot), Qcircle)) + { + /* CDR is (Center . Radius) = ((x0 . y0) . r) */ + Lisp_Object circ = XCDR (hot_spot); + Lisp_Object lr, lx0, ly0; + if (CONSP (circ) + && CONSP (XCAR (circ)) + && (lr = XCDR (circ), INTEGERP (lr) || FLOATP (lr)) + && (lx0 = XCAR (XCAR (circ)), INTEGERP (lx0)) + && (ly0 = XCDR (XCAR (circ)), INTEGERP (ly0))) + { + double r = XFLOATINT (lr); + double dx = XINT (lx0) - x; + double dy = XINT (ly0) - y; + return (dx * dx + dy * dy <= r * r); + } + } + else if (EQ (XCAR (hot_spot), Qpoly)) + { + /* CDR is [x0 y0 x1 y1 x2 y2 ...x(n-1) y(n-1)] */ + if (VECTORP (XCDR (hot_spot))) + { + struct Lisp_Vector *v = XVECTOR (XCDR (hot_spot)); + Lisp_Object *poly = v->contents; + int n = v->size; + int i; + int inside = 0; + Lisp_Object lx, ly; + int x0, y0; + + /* Need an even number of coordinates, and at least 3 edges. */ + if (n < 6 || n & 1) + return 0; + + /* Count edge segments intersecting line from (X,Y) to (X,infinity). + If count is odd, we are inside polygon. Pixels on edges + may or may not be included depending on actual geometry of the + polygon. */ + if ((lx = poly[n-2], !INTEGERP (lx)) + || (ly = poly[n-1], !INTEGERP (lx))) + return 0; + x0 = XINT (lx), y0 = XINT (ly); + for (i = 0; i < n; i += 2) + { + int x1 = x0, y1 = y0; + if ((lx = poly[i], !INTEGERP (lx)) + || (ly = poly[i+1], !INTEGERP (ly))) + return 0; + x0 = XINT (lx), y0 = XINT (ly); + + /* Does this segment cross the X line? */ + if (x0 >= x) + { + if (x1 >= x) + continue; + } + else if (x1 < x) + continue; + if (y > y0 && y > y1) + continue; + if (y < y0 + ((y1 - y0) * (x - x0)) / (x1 - x0)) + inside = !inside; + } + return inside; + } + } + else + return 0; +} + +Lisp_Object +find_hot_spot (map, x, y) + Lisp_Object map; + int x, y; +{ + while (CONSP (map)) + { + if (CONSP (XCAR (map)) + && on_hot_spot_p (XCAR (XCAR (map)), x, y)) + return XCAR (map); + map = XCDR (map); + } + + return Qnil; +} + +DEFUN ("lookup-image-map", Flookup_image_map, Slookup_image_map, + 3, 3, 0, + doc: /* Lookup in image map MAP coordinates X and Y. +An image map is an alist where each element has the format (AREA ID PLIST). +An AREA is specified as either a rectangle, a circle, or a polygon: +A rectangle is a cons (rect . ((x0 . y0) . (x1 . y1))) specifying the +pixel coordinates of the upper left and bottom right corners. +A circle is a cons (circle . ((x0 . y0) . r)) specifying the center +and the radius of the circle; r may be a float or integer. +A polygon is a cons (poly . [x0 y0 x1 y1 ...]) where each pair in the +vector describes one corner in the polygon. +Returns the alist element for the first matching AREA in MAP. */) + (map, x, y) + Lisp_Object map; + Lisp_Object x, y; +{ + int ix, iy; + if (NILP (map)) + return Qnil; + + if (!INTEGERP (x)) + wrong_type_argument (Qintegerp, x); + if (!INTEGERP (y)) + wrong_type_argument (Qintegerp, y); + + return find_hot_spot (map, XINT (x), XINT (y)); +} + + +/* Display frame CURSOR, optionally using shape defined by POINTER. */ +static void +define_frame_cursor1 (f, cursor, pointer) + struct frame *f; + Cursor cursor; + Lisp_Object pointer; +{ + if (!NILP (pointer)) + { + if (EQ (pointer, Qarrow)) + cursor = FRAME_X_OUTPUT (f)->nontext_cursor; + else if (EQ (pointer, Qhand)) + cursor = FRAME_X_OUTPUT (f)->hand_cursor; + else if (EQ (pointer, Qtext)) + cursor = FRAME_X_OUTPUT (f)->text_cursor; + else if (EQ (pointer, intern ("hdrag"))) + cursor = FRAME_X_OUTPUT (f)->horizontal_drag_cursor; +#ifdef HAVE_X_WINDOWS + else if (EQ (pointer, intern ("vdrag"))) + cursor = FRAME_X_DISPLAY_INFO (f)->vertical_scroll_bar_cursor; +#endif + else if (EQ (pointer, intern ("hourglass"))) + cursor = FRAME_X_OUTPUT (f)->hourglass_cursor; + else if (EQ (pointer, Qmodeline)) + cursor = FRAME_X_OUTPUT (f)->modeline_cursor; + else + cursor = FRAME_X_OUTPUT (f)->nontext_cursor; + } + +#ifndef HAVE_CARBON + if (cursor != No_Cursor) +#else + if (bcmp (&cursor, &No_Cursor, sizeof (Cursor))) +#endif + rif->define_frame_cursor (f, cursor); +} + /* Take proper action when mouse has moved to the mode or header line or marginal area AREA of window W, x-position X and y-position Y. X is relative to the start of the text display area of W, so the @@ -19957,18 +20167,24 @@ struct frame *f = XFRAME (w->frame); Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f); Cursor cursor = FRAME_X_OUTPUT (f)->nontext_cursor; - int charpos; - Lisp_Object string, help, map, pos; + Lisp_Object pointer = Qnil; + int charpos, dx, dy; + Lisp_Object string; + Lisp_Object pos, help, image; if (area == ON_MODE_LINE || area == ON_HEADER_LINE) string = mode_line_string (w, &x, &y, 0, 0, area, &charpos); else - string = marginal_area_string (w, &x, &y, 0, 0, area, &charpos); + { + x -= WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w); + string = marginal_area_string (w, &x, &y, &dx, &dy, area, &charpos); + } + + help = Qnil; if (STRINGP (string)) { pos = make_number (charpos); - /* If we're on a string with `help-echo' text property, arrange for the help to be displayed. This is done by setting the global variable help_echo_string to the help string. */ @@ -19981,9 +20197,13 @@ help_echo_pos = charpos; } + if (NILP (pointer)) + pointer = Fget_text_property (pos, Qpointer, string); + /* Change the mouse pointer according to what is under X/Y. */ - if (area == ON_MODE_LINE) - { + if (NILP (pointer) && area == ON_MODE_LINE) + { + Lisp_Object map; map = Fget_text_property (pos, Qlocal_map, string); if (!KEYMAPP (map)) map = Fget_text_property (pos, Qkeymap, string); @@ -19991,8 +20211,42 @@ cursor = dpyinfo->vertical_scroll_bar_cursor; } } - - rif->define_frame_cursor (f, cursor); + else if (IMAGEP (string)) + { + Lisp_Object image_map, hotspot; + if ((image_map = Fplist_get (XCDR (string), QCmap), + !NILP (image_map)) + && (hotspot = find_hot_spot (image_map, dx, dy), + CONSP (hotspot)) + && (hotspot = XCDR (hotspot), CONSP (hotspot))) + { + Lisp_Object area_id, plist; + + area_id = XCAR (hotspot); + /* Could check AREA_ID to see if we enter/leave this hot-spot. + If so, we could look for mouse-enter, mouse-leave + properties in PLIST (and do something...). */ + if ((plist = XCDR (hotspot), CONSP (plist))) + { + pointer = Fplist_get (plist, Qpointer); + if (NILP (pointer)) + pointer = Qhand; + help = Fplist_get (plist, Qhelp_echo); + if (!NILP (help)) + { + help_echo_string = help; + /* Is this correct? ++kfs */ + XSETWINDOW (help_echo_window, w); + help_echo_object = w->buffer; + help_echo_pos = charpos; + } + } + if (NILP (pointer)) + pointer = Fplist_get (XCDR (string), QCpointer); + } + } + + define_frame_cursor1 (f, cursor, pointer); } @@ -20012,6 +20266,7 @@ Lisp_Object window; struct window *w; Cursor cursor = No_Cursor; + Lisp_Object pointer = Qnil; /* Takes precedence over cursor! */ struct buffer *b; /* When a menu is active, don't highlight because this looks odd. */ @@ -20049,7 +20304,6 @@ return; /* Reset help_echo_string. It will get recomputed below. */ - /* ++KFS: X version didn't do this, but it looks harmless. */ help_echo_string = Qnil; /* Convert to window-relative pixel coordinates. */ @@ -20087,7 +20341,7 @@ && XFASTINT (w->last_modified) == BUF_MODIFF (b) && XFASTINT (w->last_overlay_modified) == BUF_OVERLAY_MODIFF (b)) { - int hpos, vpos, pos, i, area; + int hpos, vpos, pos, i, dx, dy, area; struct glyph *glyph; Lisp_Object object; Lisp_Object mouse_face = Qnil, overlay = Qnil, position; @@ -20097,7 +20351,45 @@ int obegv, ozv, same_region; /* Find the glyph under X/Y. */ - glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, &area, 0); + glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, &dx, &dy, &area); + + /* Look for :pointer property on image. */ + if (glyph != NULL && glyph->type == IMAGE_GLYPH) + { + struct image *img = IMAGE_FROM_ID (f, glyph->u.img_id); + if (img != NULL && IMAGEP (img->spec)) + { + Lisp_Object image_map, hotspot; + if ((image_map = Fplist_get (XCDR (img->spec), QCmap), + !NILP (image_map)) + && (hotspot = find_hot_spot (image_map, dx, dy), + CONSP (hotspot)) + && (hotspot = XCDR (hotspot), CONSP (hotspot))) + { + Lisp_Object area_id, plist; + + area_id = XCAR (hotspot); + /* Could check AREA_ID to see if we enter/leave this hot-spot. + If so, we could look for mouse-enter, mouse-leave + properties in PLIST (and do something...). */ + if ((plist = XCDR (hotspot), CONSP (plist))) + { + pointer = Fplist_get (plist, Qpointer); + if (NILP (pointer)) + pointer = Qhand; + help_echo_string = Fplist_get (plist, Qhelp_echo); + if (!NILP (help_echo_string)) + { + help_echo_window = window; + help_echo_object = glyph->object; + help_echo_pos = glyph->charpos; + } + } + } + if (NILP (pointer)) + pointer = Fplist_get (XCDR (img->spec), QCpointer); + } + } /* Clear mouse face if X/Y not over text. */ if (glyph == NULL @@ -20106,8 +20398,13 @@ { if (clear_mouse_face (dpyinfo)) cursor = No_Cursor; - if (NILP (Vshow_text_cursor_in_void)) - cursor = FRAME_X_OUTPUT (f)->nontext_cursor; + if (NILP (pointer)) + { + if (area != TEXT_AREA) + cursor = FRAME_X_OUTPUT (f)->nontext_cursor; + else + pointer = Vvoid_text_area_pointer; + } goto set_cursor; } @@ -20120,9 +20417,6 @@ if (BUFFERP (object) && pos > BUF_Z (b)) goto set_cursor; - if (glyph->type == IMAGE_GLYPH) - cursor = FRAME_X_OUTPUT (f)->nontext_cursor; - /* Make the window's buffer temporarily current for overlays_at and compute_char_face. */ obuf = current_buffer; @@ -20366,7 +20660,7 @@ check_help_echo: /* Look for a `help-echo' property. */ - { + if (NILP (help_echo_string)) { Lisp_Object help, overlay; /* Check overlays first. */ @@ -20432,6 +20726,46 @@ } } + /* Look for a `pointer' property. */ + if (NILP (pointer)) + { + /* Check overlays first. */ + for (i = noverlays - 1; i >= 0 && NILP (pointer); --i) + pointer = Foverlay_get (overlay_vec[i], Qpointer); + + if (NILP (pointer)) + { + Lisp_Object object = glyph->object; + int charpos = glyph->charpos; + + /* Try text properties. */ + if (STRINGP (object) + && charpos >= 0 + && charpos < SCHARS (object)) + { + pointer = Fget_text_property (make_number (charpos), + Qpointer, object); + if (NILP (pointer)) + { + /* If the string itself doesn't specify a pointer, + see if the buffer text ``under'' it does. */ + struct glyph_row *r + = MATRIX_ROW (w->current_matrix, vpos); + int start = MATRIX_ROW_START_CHARPOS (r); + int pos = string_buffer_position (w, object, start); + if (pos > 0) + pointer = Fget_char_property (make_number (pos), + Qpointer, w->buffer); + } + } + else if (BUFFERP (object) + && charpos >= BEGV + && charpos < ZV) + pointer = Fget_text_property (make_number (charpos), + Qpointer, object); + } + } + BEGV = obegv; ZV = ozv; current_buffer = obuf; @@ -20439,12 +20773,7 @@ set_cursor: -#ifndef HAVE_CARBON - if (cursor != No_Cursor) -#else - if (bcmp (&cursor, &No_Cursor, sizeof (Cursor))) -#endif - rif->define_frame_cursor (f, cursor); + define_frame_cursor1 (f, cursor, pointer); } @@ -21040,6 +21369,7 @@ #endif #ifdef HAVE_WINDOW_SYSTEM defsubr (&Stool_bar_lines_needed); + defsubr (&Slookup_image_map); #endif defsubr (&Sformat_mode_line); @@ -21073,16 +21403,14 @@ staticpro (&Qspace); Qmargin = intern ("margin"); staticpro (&Qmargin); + Qpointer = intern ("pointer"); + staticpro (&Qpointer); Qleft_margin = intern ("left-margin"); staticpro (&Qleft_margin); Qright_margin = intern ("right-margin"); staticpro (&Qright_margin); - Qalign_to = intern ("align-to"); - staticpro (&Qalign_to); QCalign_to = intern (":align-to"); staticpro (&QCalign_to); - Qrelative_width = intern ("relative-width"); - staticpro (&Qrelative_width); QCrelative_width = intern (":relative-width"); staticpro (&QCrelative_width); QCrelative_height = intern (":relative-height"); @@ -21101,6 +21429,16 @@ staticpro (&Qtrailing_whitespace); Qimage = intern ("image"); staticpro (&Qimage); + QCmap = intern (":map"); + staticpro (&QCmap); + QCpointer = intern (":pointer"); + staticpro (&QCpointer); + Qrect = intern ("rect"); + staticpro (&Qrect); + Qcircle = intern ("circle"); + staticpro (&Qcircle); + Qpoly = intern ("poly"); + staticpro (&Qpoly); Qmessage_truncate_lines = intern ("message-truncate-lines"); staticpro (&Qmessage_truncate_lines); Qcursor_in_non_selected_windows = intern ("cursor-in-non-selected-windows"); @@ -21125,6 +21463,12 @@ staticpro (&Qbox); Qhollow = intern ("hollow"); staticpro (&Qhollow); + Qhand = intern ("hand"); + staticpro (&Qhand); + Qarrow = intern ("arrow"); + staticpro (&Qarrow); + Qtext = intern ("text"); + staticpro (&Qtext); Qrisky_local_variable = intern ("risky-local-variable"); staticpro (&Qrisky_local_variable); Qinhibit_free_realized_faces = intern ("inhibit-free-realized-faces"); @@ -21178,10 +21522,11 @@ The face used for trailing whitespace is `trailing-whitespace'. */); Vshow_trailing_whitespace = Qnil; - DEFVAR_LISP ("show-text-cursor-in-void", &Vshow_text_cursor_in_void, - doc: /* Non-nil means show the text cursor in void text areas. -The default is to show the non-text (typically arrow) cursor. */); - Vshow_text_cursor_in_void = Qnil; + DEFVAR_LISP ("void-text-area-pointer", &Vvoid_text_area_pointer, + doc: /* The pointer shape to show in void text areas. +Nil means to show the text pointer. Other options are `arrow', `text', +`hand', `vdrag', `hdrag', `modeline', and `hourglass'. */); + Vvoid_text_area_pointer = Qarrow; DEFVAR_LISP ("inhibit-redisplay", &Vinhibit_redisplay, doc: /* Non-nil means don't actually do any redisplay.
--- a/src/xfaces.c Sun Dec 28 16:04:37 2003 +0000 +++ b/src/xfaces.c Sun Dec 28 16:05:28 2003 +0000 @@ -5579,12 +5579,19 @@ face->id = i; /* Maybe enlarge C->faces_by_id. */ - if (i == c->used && c->used == c->size) - { - int new_size = 2 * c->size; - int sz = new_size * sizeof *c->faces_by_id; - c->faces_by_id = (struct face **) xrealloc (c->faces_by_id, sz); - c->size = new_size; + if (i == c->used) + { + if (c->used == c->size) + { + int new_size, sz; + new_size = min (2 * c->size, MAX_FACE_ID); + if (new_size == c->size) + abort (); /* Alternatives? ++kfs */ + sz = new_size * sizeof *c->faces_by_id; + c->faces_by_id = (struct face **) xrealloc (c->faces_by_id, sz); + c->size = new_size; + } + c->used++; } #if GLYPH_DEBUG @@ -5603,8 +5610,6 @@ #endif /* GLYPH_DEBUG */ c->faces_by_id[i] = face; - if (i == c->used) - ++c->used; }
--- a/src/xfns.c Sun Dec 28 16:04:37 2003 +0000 +++ b/src/xfns.c Sun Dec 28 16:05:28 2003 +0000 @@ -1302,7 +1302,6 @@ hourglass_cursor = XCreateFontCursor (dpy, XC_watch); x_check_errors (dpy, "bad hourglass pointer cursor: %s"); - x_check_errors (dpy, "bad nontext pointer cursor: %s"); if (!NILP (Vx_mode_pointer_shape)) { CHECK_NUMBER (Vx_mode_pointer_shape); @@ -4418,11 +4417,6 @@ static struct image_type *image_types; -/* The symbol `image' which is the car of the lists used to represent - images in Lisp. */ - -extern Lisp_Object Qimage; - /* The symbol `xbm' which is used as the type symbol for XBM images. */ Lisp_Object Qxbm; @@ -4502,7 +4496,7 @@ { int valid_p = 0; - if (CONSP (object) && EQ (XCAR (object), Qimage)) + if (IMAGEP (object)) { Lisp_Object tem; @@ -4604,7 +4598,7 @@ int i; Lisp_Object plist; - if (!CONSP (spec) || !EQ (XCAR (spec), Qimage)) + if (!IMAGEP (spec)) return 0; plist = XCDR (spec);
--- a/src/xmenu.c Sun Dec 28 16:04:37 2003 +0000 +++ b/src/xmenu.c Sun Dec 28 16:05:28 2003 +0000 @@ -99,7 +99,6 @@ Lisp_Object Qdebug_on_next_call; extern Lisp_Object Qmenu_bar; -extern Lisp_Object Qmouse_click, Qevent_kind; extern Lisp_Object QCtoggle, QCradio; @@ -1304,6 +1303,7 @@ } else { +#if 0 /* This code doesn't do anything useful. ++kfs */ /* WIDGET is the popup menu. It's parent is the frame's widget. See which frame that is. */ xt_or_gtk_widget frame_widget = XtParent (widget); @@ -1317,7 +1317,7 @@ FRAME_X_P (f) && f->output_data.x->widget == frame_widget)) break; } - +#endif show_help_echo (help, Qnil, Qnil, Qnil, 1); } }
--- a/src/xterm.c Sun Dec 28 16:04:37 2003 +0000 +++ b/src/xterm.c Sun Dec 28 16:05:28 2003 +0000 @@ -287,7 +287,7 @@ extern Lisp_Object Vx_no_window_manager; -extern Lisp_Object Qface, Qmouse_face, Qeql; +extern Lisp_Object Qeql; extern int errno; @@ -7270,13 +7270,6 @@ struct glyph *cursor_glyph; GC gc; - /* Compute frame-relative coordinates from window-relative - coordinates. */ - x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x); - y = (WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y) - + row->ascent - w->phys_cursor_ascent); - h = row->height - 1; - /* Get the glyph the cursor is on. If we can't tell because the current matrix is invalid or such, give up. */ cursor_glyph = get_phys_cursor_glyph (w); @@ -7293,6 +7286,19 @@ wd = min (FRAME_COLUMN_WIDTH (f), wd); w->phys_cursor_width = wd; + /* Compute frame-relative coordinates from window-relative + coordinates. */ + x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x); + y = WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y); + + /* Compute the proper height and ascent of the rectangle, based + on the actual glyph. Using the full height of the row looks + bad when there are tall images on that row. */ + h = max (FRAME_LINE_HEIGHT (f), cursor_glyph->ascent + cursor_glyph->descent); + if (h < row->height) + y += row->ascent /* - w->phys_cursor_ascent */ + cursor_glyph->descent - h; + h--; + /* The foreground of cursor_gc is typically the same as the normal background color, which can cause the cursor box to be invisible. */ xgcv.foreground = f->output_data.x->cursor_pixel;