;;; cscope.el --- Interface to cscope browser ;; Author: Bill Carpenter. ;; [Note by Stephen Eglen, Tue 19 Aug 2003. I am placing this on ;; emacswiki.org with Bill's permission so that it gets archived. ;; Note that I have edited the original version of ;; cscope-bind-keys-3deep to allow C-c C-s to work with modern ;; (> 1996) versions of the default C mode. See ;; http://cscope.sourceforge.net for details on cscope and another ;; Emacs interface. ;; This is free software. ;; The above line was added to satisfy emacswiki.org; see below for an ;; elaboration on what can be done with this source.] ;; original: /anonymous@src.doc.ic.ac.uk:/gnu/EmacsBits/elisp-archive/interfaces/cscope.el.Z ;; From billc@pegasus.ATT.COM Mon Nov 11 20:53:08 1991 ;; Xref: cbnewsh comp.emacs:7861 gnu.emacs.sources:558 ;; Newsgroups: comp.emacs,gnu.emacs.sources ;; Path: cbnewsh!hos1cad!billc ;; From: billc@pegasus.ATT.COM (Bill Carpenter) ;; Subject: GNUemacs-to-cscope interface, cscope.el ;; Organization: AT&T Bell Laboratories ;; Date: Tue, 12 Nov 1991 01:51:45 GMT ;; Message-ID: <1991Nov12.015145.9840@cbnewsh.cb.att.com> ;; Sender: bill@cbnewsh.cb.att.com (william.j.carpenter) ;; Lines: 909 ;; This is an interface from GNUemacs to Joe Steffen's "cscope" C browser. ;; With this code, you can do things like put your cursor on some C ;; symbol, hit a couple keys and be transported anyplace special that ;; cscope knows about. See the variable cscope-blurb for more general info. ;; ;; If you use this, I am interested in hearing from you how it went, ;; especially if you find bugs or if you use cscope in some way that ;; this interface doesn't support (or doesn't support very well). ;; ;; Bill William_J_Carpenter@ATT.COM or ;; (908) 576-2932 attmail!bill or att!pegasus!billc ;; AT&T Bell Labs / AT&T EasyLink Services LZ 1E-207 ;;cscope.el ;; ;;; ;;; LCD Archive Entry: ;;; cscope|Bill Carpenter|William_J_Carpenter@ATT.COM ;;; |Interface to cscope browser ;;; |91-11-11|1|~/interfaces/cscope.el.Z| ;;; ;;; patchlevel 0, 13-Oct-91 (beta) ;;; patchlevel 1, 11-Nov-91 first general release ;;; ;;; As far as I'm concerned, anyone can do anything they want with ;;; this specific piece of code. No warranty or promise of support is ;;; offered. I am interested in hearing reports of bugs or interesting ;;; uses. Suggestions for interesting enhancements are welcome. ;;; My thanks to the beta testers. I am especially appreciative of ;;; the helpful feedback received about earlier versions of this from ;;; Mike Balenger and Neal McBurnett. (defconst cscope-version "patchlevel 1, 11 Nov 91") (defvar cscope-bindings-2deep nil "*If non-nil, then two character bindings are applied when \"cscope-bind-keys\" is called. The two character bindings are mostly of the form \"C-c letter\". The reason they are optional is that there is an elisp coding convention which suggests that those kinds of bindings should be reserved for users. The binding of \"C-c C-c\" is not controlled by this user option variable; it is always applied.") (defvar cscope-bindings-3deep t "*If non-nil, then three character bindings are applied when \"cscope-bind-keys\" is called. The three character bindings are mostly of the form \"C-c C-s letter\".") (defvar cscope-bind-keys-hook nil "At the end of the function \"cscope-find-keys\", this hook is run. This provides an opportunity for custom keybinding schemes as well as any other buffer-specific set-up. In cscope output buffers, this hook is run before the extra bindings are applied; however, since those extra bindings are all in \"cscope-keymap\", they can be modified directly by the user to affect all cscope output buffers.") (defvar cscope-quit-hook nil "Called after a cscope subprocess is told to exit. If called as part of a command that also kills the buffer, the hook is run before the buffer is killed.") (defvar cscope-b-and-f-hook nil "Run after the user bounces back to the cscope output buffer from a source file. This hook is run after the cursor has been positoned. It gives the user an opportunity to use some other cursor positioning strategy instead of just advancing to the next line.") (defvar cscope-interpret-output-hook nil "Run after the user moves from a cscope output line to the referenced source file. This hook is run after the cursor has been positoned. It gives the user an opportunity to use some other cursor positioning strategy.") (defvar cscope-query-hook nil "Run after a query has been made of the cscope subprocess. Normally, the cscope interface tries to position the cursor at the first cscope result line, but it is possible for it to miss. This hook allows an alternate cursor positioning strategy or any other after-the-query processing. For example, if you felt like it, you could \"pre-visit\" all the files mentioned in output lines. More usefully, you might like to automatically visit a referenced source file line if there is only one output line from cscope.") (defvar cscope-file-not-found-hook nil "If defined, this behaves slightly differently than a standard emacs hook function. It is run instead of (not in addition to) the normal action taken if some referenced source file can't be found. Normally, (if this hook is not defined) the cscope interface will signal an error and give up looking.") (defvar cscope-filename-fixxer-raw nil "If defined as a function, called to generate a filename. The single argument is a raw filename reference as taken from a cscope output buffer. The expected return value is something that the cscope interface will try to resolve into a full pathname (using mechanisms desribed elsewhere).") (defvar cscope-filename-fixxer-cooked nil "If defined as a function, called to generate a filename. The single argument is a cooked filename reference, meaning that the cscope interface has already tried to resolve it into a full pathname (using mechanisms described elsewhere). Since the resolution doesn't always succeed, the argument might not be a full pathname. The expected return value is something that the cscope interface will try to visit with \"find-file\".") (defvar cscope-blurb nil "This is an interface from GNUemacs to the line-oriented mode of Joe Steffen's cscope, a C code browser (cscope itself is available from the AT&T Toolchest). The interface includes provisions for having multiple concurrent unrelated cscope sessions. For casual use, arrange for this file to be loaded and call the function \"cscope-bind-keys\". See the documentation for \"cscope-bind-keys\" for more information about that. If you are inclined to have multiple cscope sessions, possibly with different invocation command lines or using pre-built databases, then see the documentation for cscope-master-info-table and cscope-master-info-default. The general method of using this is to arrange for the cscope-related bindings to be made, place the cursor over some symbol or filename in question, and invoke the appropriate cscope function. This will invoke a cscope subprocess (if it's not already running) and perform the query. The results of the query are presented in a cscope output buffer. The user can place the cursor over a cscope reference line and type \"C-c C-c\" to move to the referenced location. After that, the user can type \"C-c C-c\" again and move back to the cscope output buffer, automatically advancing the cursor to the next line. Functions that cause other buffers to be displayed generally pop them up in another window. If those functions are called with prefix arguments, then the summoned buffer is put in the currently selected window. A good way to arrange for this file to be loaded is via c-mode-hook. This file \"provides\" cscope, so you can use \"require\" directives and/or autoloading. Here's a example: (autoload 'cscope-bind-keys \"cscope\" nil t) (defun wjc:c-mode-hook () \"my C mode hook\" ;; only bother doing the bindings first time ... they'll stick (or (where-is-internal 'cscope-find-c-symbol (current-local-map)) (cscope-bind-keys)) ;; (and (boundp 'cscope-blurb) (makunbound 'cscope-blurb)) (local-set-key \"\\M-?\" 'cscope-find-c-symbol)) (setq c-mode-hook 'wjc:c-mode-hook) If you've seen the information in the description of this user option variable enough times, you can let emacs reclaim the string space by doing (makunbound 'cscope-blurb) after the cscope interface is loaded (shown as a commented line in the above example). Even if you don't have handy the source file, cscope.el, you'll still be able to read the docstrings in cscope.elc.") (defvar cscope-master-info-table nil "*A list-of-lists telling how to run cscope for a given buffer. If you're not doing anything fancy with the cscope interface, like browsing multiple databases concurrently, then you probably don't need to set this. Each item in \"cscope-master-info-table\" is a list. Trailing nil items from the sublists may be omitted. The first item in each sublist is a string which acts as the key for that sublist. If the value of the buffer-local variable \"cscope-id\" matches the key, then that sublist is used to decide how to run cscope for that buffer. If no sublist in the entire table matches \"cscope-id\", then \"cscope-master-info-default\" is used. The second item in each sublist is itself a list. It's a list of strings which comprise the command line and arguments for invoking cscope. See the cscope man page for valid command line arguments. Don't forget to make sure that cscope and/or user-specified cscope commands are available via the PATH environment variable. The third item in each sublist is an optional \"cd place\". If a non-nil string, the current directory will be temporarily changed to the directory named while cscope is being invoked (ie, while the cscope subprocess is being spawned). After cscope is invoked, the current directory is returned to whatever it was before. The fourth item in each sublist is a user-specified path prefix. A cscope database might only know relative pathnames. Some versions of cscope can be queried for the path prefix to use with relative pathnames, but this does not work with all versions. If cscope tells emacs about a filename that is a relative pathname, the automatically known path prefix is prepended. If there is no automatically known path prefix, the user-specified path prefix is used. If there is no user-specified path prefix, the \"cd place\" is used. Otherwise, the unprefixed relative pathname is used. Here's an example of a personal setting for this variable: (setq cscope-master-info-table '( (\"projA\" (\"cscope\" \"-l\" \"-d\" \"-f\" \"/projA/src/cscope.out\")) (\"projB\" (\"cscope\" \"-l\" \"-d\" \"-f\" \"/projB/src/cscope.out\")) )) The example uses separate pre-built cscope databases for projects \"projA\" and \"projB\". The last two items in the sublists are nil (because they're not specified), which is a good clue that the databases were built knowing full pathnames. For buffers that are not \"projA\" or \"projB\", the default cscope invocation will be used.") (defvar cscope-master-info-default '("CSCOPE" ("cscope" "-l") nil nil) "*When a search of \"cscope-master-info-table\" is done and no match is found, the list specified by this variable is returned instead. See the documentation for \"cscope-master-info-table\" for an explanation of the items in the list.") (defvar cscope-id nil "*Used as a key into \"cscope-master-info-table\". This is a buffer-local variable and could be set manually or by some mode-specific hook function. If this variable is not explicitly set, it will generally result in the use of \"cscope-master-info-default\". The value of \"cscope-id\" follows from buffer to buffer, but will not override any previously set values. That is, if a given buffer has a cscope-id of \"foo\", a cscope output buffer for a cscope process started from that buffer will also get a cscope-id of \"foo\". Any source files newly visited as a result of cscope queries from that cscope process will also get a cscope-id of \"foo\". Users can overcome that by explicitly setting cscope-id via some hook or other means. \"cscope-id\" is buffer-local, so if you kill-all-local-variables, the value will be lost.") (make-variable-buffer-local 'cscope-id) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; most users need not explore below here except to read function ; documentation strings; you can just as well describe-function ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defvar cscope-output-line-regexp "\\s-*\\(\\S-+\\)\\s-+\\(\\S-+\\)\\s-+\\([0-9]+\\)" "*This regular expression is used to recognize valid reference lines of output from the output of the line-oriented mode of cscope. It must include subexpressions which obtain the filename, function name, and line number.") (defvar cscope-output-file-place 1 "*Position number of the \"cscope-output-line-regexp\" subexpression which locates the filename.") (defvar cscope-output-func-place 2 "*Position number of the \"cscope-output-line-regexp\" subexpression which locates the function name.") (defvar cscope-output-line-place 3 "*Position number of the \"cscope-output-line-regexp\" subexpression which locates the line number.") (defvar cscope-c-symbol-regexp "[a-zA-Z0-9_]+" "*A regular expression specifying a legitimate C symbol. Used for finding a default symbol for minibuffer prompting. User input need not conform to this regular expression.") (defvar cscope-filename-regexp "[a-zA-Z0-9_.-]+" "*A regular expression specifying a legitimate file name. Used for finding a default filename for minibuffer prompting. User input need not conform to this regular expression.") ; macros for pulling items out of sublists from cscope-master-info-table (defmacro cscope:label-of-list (cl) (list 'nth 0 cl)) (defmacro cscope:command-of-list (cl) (list 'nth 1 cl)) (defmacro cscope:cdplace-of-list (cl) (list 'nth 2 cl)) (defmacro cscope:pathprefix-of-list (cl) (list 'nth 3 cl)) (defun cscope-bind-keys () "Establish the key bindings for cscope queries and interactions. A reasonable thing to do is to call this function from \"c-mode-hook\". However, if you use a minor mode which changes the keymap, you may have to take extra steps. For example, \"view-mode\" installs its own keymap and is often called via \"find-file-hooks\". For that particular case, it may be helpful to have a line something like this automatically invoked after \"view-mode\" has been installed: (if (eq major-mode 'c-mode) (cscope-bind-keys)) Keys bound by invoking this function can be listed by going to a buffer where the bindings are active and doing \\[describe-bindings]. They usually begin with a C-c C-s prefix. If \"cscope-bindings-2deep\" is non-nil, then you will see bindings of the form \"C-c letter\". If \"cscope-bindings-3deep\" is non-nil (the default), you will see bindings of the form \"C-c C-s letter\". These settings are independent of one another, and by default the three character bindings are provided and the two character bindings are not. The bindings are put in place by modifying whatever keymaps happen to be in effect whenever you invoke this function. For most users, this will mean it's a more or less global change (e.g., to \"c-mode-map\"). In any case, the binding of \"C-c C-c\" is provided. After the bindings have been made, the optional user-supplied \"cscope-bind-keys-hook\" is run. In cscope output buffers, there are additional single character bindings (not controlled by any user option variable). Further, the two and/or three character bindings are provided, depending on the values of the \"cscope-bindings-2deep\" and \"cscope-bindings-3deep\" at the time the cscope interface is first loaded. A different binding is given to \"C-c C-c\" in cscope output buffers. Within each set of bindings, more than one binding is made for some functions for convenience. Use \\[describe-bindings] to get a complete list. The intent of the alternate bindings of cscope-interpret-output-line and cscope-goback-and-goforth in different buffer types is so that an interested user can step through references in a cscope output buffer by repeatedly typing the same keys." (interactive) (if cscope-bindings-2deep (cscope-bind-keys-2deep)) (if cscope-bindings-3deep (cscope-bind-keys-3deep)) (local-set-key "\C-c\C-c" 'cscope-goback-and-goforth) (run-hooks 'cscope-bind-keys-hook) ) (defun cscope-bind-keys-2deep () (interactive) "Apply two character cscope bindings to the currently active keymap. The bindings are of the form \"C-c letter\" See variable \"cscope-bindings-2deep\"." (local-set-key "\C-cc" 'cscope-find-c-symbol) (local-set-key "\C-cC" 'cscope-find-c-symbol) ;; (local-set-key "\C-c\C-c" 'cscope-find-c-symbol) (local-set-key "\C-cd" 'cscope-find-global-definition) (local-set-key "\C-cD" 'cscope-find-global-definition) (local-set-key "\C-c\C-d" 'cscope-find-global-definition) (local-set-key "\C-cv" 'cscope-find-functions-called) (local-set-key "\C-cV" 'cscope-find-functions-called) (local-set-key "\C-c\C-v" 'cscope-find-functions-called) (local-set-key "\C-c^" 'cscope-find-functions-calling) (local-set-key "\C-c6" 'cscope-find-functions-calling) (local-set-key "\C-ct" 'cscope-find-text-string) (local-set-key "\C-cT" 'cscope-find-text-string) (local-set-key "\C-c\C-t" 'cscope-find-text-string) (local-set-key "\C-cg" 'cscope-find-grep-pattern) (local-set-key "\C-cG" 'cscope-find-grep-pattern) (local-set-key "\C-c\C-g" 'cscope-find-grep-pattern) (local-set-key "\C-ce" 'cscope-find-egrep-pattern) (local-set-key "\C-cE" 'cscope-find-egrep-pattern) (local-set-key "\C-c\C-e" 'cscope-find-egrep-pattern) (local-set-key "\C-cf" 'cscope-find-file) (local-set-key "\C-cF" 'cscope-find-file) (local-set-key "\C-c\C-f" 'cscope-find-file) (local-set-key "\C-ci" 'cscope-find-files-including) (local-set-key "\C-cI" 'cscope-find-files-including) (local-set-key "\C-c\C-i" 'cscope-find-files-including) (local-set-key "\C-c#" 'cscope-find-files-including) (local-set-key "\C-c3" 'cscope-find-files-including) (local-set-key "\C-c*" 'cscope-find-all) (local-set-key "\C-c8" 'cscope-find-all) (local-set-key "\C-ca" 'cscope-admin-toggle-case) (local-set-key "\C-cA" 'cscope-admin-toggle-case) (local-set-key "\C-c\C-a" 'cscope-admin-toggle-case) (local-set-key "\C-cr" 'cscope-admin-rebuild-db) (local-set-key "\C-cR" 'cscope-admin-rebuild-db) (local-set-key "\C-c\C-r" 'cscope-admin-rebuild-db) (local-set-key "\C-cp" 'cscope-query-path-prefix) (local-set-key "\C-cP" 'cscope-query-path-prefix) (local-set-key "\C-c\C-p" 'cscope-query-path-prefix) (local-set-key "\C-cx" 'cscope-admin-quit) (local-set-key "\C-cX" 'cscope-admin-quit) (local-set-key "\C-c\C-x" 'cscope-admin-quit) (local-set-key "\C-cq" 'cscope-admin-quit-and-kill-buffer) (local-set-key "\C-cQ" 'cscope-admin-quit-and-kill-buffer) (local-set-key "\C-c\C-q" 'cscope-admin-quit-and-kill-buffer) ) (defun cscope-bind-keys-3deep () (interactive) "Apply three character cscope bindings to the currently active keymap. The bindings are of the form \"C-c C-s letter\" See variable \"cscope-bindings-3deep\"." (local-unset-key ""); SJE MOD Mon Jun 24 1996 ; to stop cc-mode getting at c-c c-s (local-set-key "\C-c\C-sc" 'cscope-find-c-symbol) (local-set-key "\C-c\C-sC" 'cscope-find-c-symbol) (local-set-key "\C-c\C-s\C-c" 'cscope-find-c-symbol) (local-set-key "\C-c\C-sd" 'cscope-find-global-definition) (local-set-key "\C-c\C-sD" 'cscope-find-global-definition) (local-set-key "\C-c\C-s\C-d" 'cscope-find-global-definition) (local-set-key "\C-c\C-sv" 'cscope-find-functions-called) (local-set-key "\C-c\C-sV" 'cscope-find-functions-called) (local-set-key "\C-c\C-s\C-v" 'cscope-find-functions-called) (local-set-key "\C-c\C-s^" 'cscope-find-functions-calling) (local-set-key "\C-c\C-s6" 'cscope-find-functions-calling) (local-set-key "\C-c\C-st" 'cscope-find-text-string) (local-set-key "\C-c\C-sT" 'cscope-find-text-string) (local-set-key "\C-c\C-s\C-t" 'cscope-find-text-string) (local-set-key "\C-c\C-sg" 'cscope-find-grep-pattern) (local-set-key "\C-c\C-sG" 'cscope-find-grep-pattern) (local-set-key "\C-c\C-s\C-g" 'cscope-find-grep-pattern) (local-set-key "\C-c\C-se" 'cscope-find-egrep-pattern) (local-set-key "\C-c\C-sE" 'cscope-find-egrep-pattern) (local-set-key "\C-c\C-s\C-e" 'cscope-find-egrep-pattern) (local-set-key "\C-c\C-sf" 'cscope-find-file) (local-set-key "\C-c\C-sF" 'cscope-find-file) (local-set-key "\C-c\C-s\C-f" 'cscope-find-file) (local-set-key "\C-c\C-si" 'cscope-find-files-including) (local-set-key "\C-c\C-sI" 'cscope-find-files-including) (local-set-key "\C-c\C-s\C-i" 'cscope-find-files-including) (local-set-key "\C-c\C-s#" 'cscope-find-files-including) (local-set-key "\C-c\C-s3" 'cscope-find-files-including) (local-set-key "\C-c\C-s*" 'cscope-find-all) (local-set-key "\C-c\C-s8" 'cscope-find-all) (local-set-key "\C-c\C-sa" 'cscope-admin-toggle-case) (local-set-key "\C-c\C-sA" 'cscope-admin-toggle-case) (local-set-key "\C-c\C-s\C-a" 'cscope-admin-toggle-case) (local-set-key "\C-c\C-sr" 'cscope-admin-rebuild-db) (local-set-key "\C-c\C-sR" 'cscope-admin-rebuild-db) (local-set-key "\C-c\C-s\C-r" 'cscope-admin-rebuild-db) (local-set-key "\C-c\C-sp" 'cscope-query-path-prefix) (local-set-key "\C-c\C-sP" 'cscope-query-path-prefix) (local-set-key "\C-c\C-s\C-p" 'cscope-query-path-prefix) (local-set-key "\C-c\C-sx" 'cscope-admin-quit) (local-set-key "\C-c\C-sX" 'cscope-admin-quit) (local-set-key "\C-c\C-s\C-x" 'cscope-admin-quit) (local-set-key "\C-c\C-sq" 'cscope-admin-quit-and-kill-buffer) (local-set-key "\C-c\C-sQ" 'cscope-admin-quit-and-kill-buffer) (local-set-key "\C-c\C-s\C-q" 'cscope-admin-quit-and-kill-buffer) ) (if (not (boundp 'cscope-keymap)) (progn (setq cscope-keymap (copy-keymap text-mode-map)) (let ((real-keymap (current-local-map))) (use-local-map cscope-keymap) (cscope-bind-keys) (use-local-map real-keymap)) (define-key cscope-keymap "c" 'cscope-find-c-symbol) (define-key cscope-keymap "C" 'cscope-find-c-symbol) (define-key cscope-keymap "d" 'cscope-find-global-definition) (define-key cscope-keymap "D" 'cscope-find-global-definition) (define-key cscope-keymap "v" 'cscope-find-functions-called) (define-key cscope-keymap "V" 'cscope-find-functions-called) (define-key cscope-keymap "^" 'cscope-find-functions-calling) (define-key cscope-keymap "t" 'cscope-find-text-string) (define-key cscope-keymap "T" 'cscope-find-text-string) (define-key cscope-keymap "g" 'cscope-find-grep-pattern) (define-key cscope-keymap "G" 'cscope-find-grep-pattern) (define-key cscope-keymap "e" 'cscope-find-egrep-pattern) (define-key cscope-keymap "E" 'cscope-find-egrep-pattern) (define-key cscope-keymap "f" 'cscope-find-file) (define-key cscope-keymap "F" 'cscope-find-file) (define-key cscope-keymap "i" 'cscope-find-files-including) (define-key cscope-keymap "I" 'cscope-find-files-including) (define-key cscope-keymap "#" 'cscope-find-files-including) (define-key cscope-keymap "*" 'cscope-find-all) (define-key cscope-keymap "a" 'cscope-admin-toggle-case) (define-key cscope-keymap "A" 'cscope-admin-toggle-case) (define-key cscope-keymap "r" 'cscope-admin-rebuild-db) (define-key cscope-keymap "R" 'cscope-admin-rebuild-db) (define-key cscope-keymap "p" 'cscope-query-path-prefix) (define-key cscope-keymap "P" 'cscope-query-path-prefix) (define-key cscope-keymap "x" 'cscope-admin-quit) (define-key cscope-keymap "X" 'cscope-admin-quit) (define-key cscope-keymap "q" 'cscope-admin-quit-and-kill-buffer) (define-key cscope-keymap "Q" 'cscope-admin-quit-and-kill-buffer) (define-key cscope-keymap "\C-c\C-c" 'cscope-interpret-output-line) (define-key cscope-keymap "\C-m" 'cscope-interpret-output-line) )) (defun cscope-find-c-symbol (symbol) "Query cscope for the whereabouts of the given symbol. When called interactively, the user is prompted for the symbol name, with a symbol near point being the default. A prefix argument causes the current window to be used for the output." (interactive (cscope:gather-c-symbol "0")) (cscope:query-omnibus "0" symbol)) ;; 0 0 (defun cscope-find-global-definition (symbol) "Query cscope for the global definition of the given symbol. When called interactively, the user is prompted for the symbol name, with a symbol near point being the default. A prefix argument causes the current window to be used for the output." (interactive (cscope:gather-c-symbol "1")) (cscope:query-omnibus "1" symbol)) ;; 1 x (defun cscope-find-functions-called (symbol) "Query cscope for the names of functions called by a function. When called interactively, the user is prompted for the function name, with a symbol near point being the default. A prefix argument causes the current window to be used for the output." (interactive (cscope:gather-c-symbol "1")) (cscope:query-omnibus "1" symbol)) ;; 2 1 (defun cscope-find-functions-calling (symbol) "Query cscope for the names of functions calling a function. When called interactively, the user is prompted for the function name, with a symbol near point being the default. A prefix argument causes the current window to be used for the output." (interactive (cscope:gather-c-symbol "2")) (cscope:query-omnibus "2" symbol)) ;; 3 2 (defun cscope-find-text-string (symbol) "Query cscope for the whereabouts of the given text string. When called interactively, the user is prompted for the string. A prefix argument causes the current window to be used for the output." (interactive (cscope:gather-text-string "3")) (cscope:query-omnibus "3" symbol)) ;; 4 3 (defun cscope-find-grep-pattern (symbol) "Query cscope for the whereabouts of the given grep pattern. When called interactively, the user is prompted for the pattern. (The line-oriented mode of cscope does not support changing occurrences of the given pattern; the full-screen version of cscope does.) A prefix argument causes the current window to be used for the output." (interactive (cscope:gather-text-string "5")) (cscope:query-omnibus "5" symbol)) ;; 5 x (defun cscope-find-egrep-pattern (symbol) "Query cscope for the whereabouts of the given egrep pattern. When called interactively, the user is prompted for the pattern. A prefix argument causes the current window to be used for the output." (interactive (cscope:gather-text-string "6")) (cscope:query-omnibus "6" symbol)) ;; 6 x (defun cscope-find-file (symbol) "Query cscope for the whereabouts of the given file. When called interactively, the user is prompted for the file name, with a symbol near point being the default. A prefix argument causes the current window to be used for the output." (interactive (cscope:gather-file-name "5")) (cscope:query-omnibus "5" symbol)) ;; 7 5 (defun cscope-find-files-including (symbol) "Query cscope for the files including a given file. When called interactively, the user is prompted for the file name, with a symbol near point being the default. A prefix argument causes the current window to be used for the output." (interactive (cscope:gather-file-name "4")) (cscope:query-omnibus "4" symbol)) ;; 8 4 (defun cscope-find-all (&rest symbol) "Query cscope for the definitions of all functions and C++ classes. Any arguments to this function are ignored. A prefix argument causes the current window to be used for the output." (interactive) (cscope:query-omnibus "9" "fake")) ;; 9 x (defun cscope-admin-toggle-case (&rest symbol) "Toggle case-folding for subsequent cscope searches. Since case-folding can also be affected by a command line option when cscope is invoked, it's up to the user to keep track of the state of the toggle. Any arguments to this function are ignored. A prefix argument causes the current window to be used for the output." (interactive) (cscope:query-omnibus "c")) ;; c x (defun cscope-admin-rebuild-db (&rest symbol) "Tell the cscope subprocess to rebuild its database. Any arguments to this function are ignored. A prefix argument causes the current window to be used for the output." (interactive) (cscope:query-omnibus "r")) ;; r r (defun cscope-query-path-prefix (&rest symbol) "Query cscope for the relative filename path prefix. Not all versions of cscope support this feature; if yours doesn't, it will be obvious from what you see in the cscope output buffer after running this command. Any arguments to this function are ignored. A prefix argument causes the current window to be used for the output." (interactive) (cscope:query-omnibus "P")) ;; P x (defun cscope-admin-quit (&rest symbol) "Tell the cscope subprocess to terminate. Any arguments to this function are ignored. Afterwards, run the optional user-supplied \"cscope-quit-hook\". A prefix argument causes the current window to be used for the output." (interactive) (prog1 (cscope:query-omnibus "q") (run-hooks 'cscope-quit-hook) )) ;; q q (defun cscope-admin-quit-and-kill-buffer (&rest symbol) "Tell the cscope subprocess to terminate. You can achieve the same effect by simply killing the affiliated cscope output buffer or by exiting emacs. Any arguments to this function are ignored." (interactive) (cscope-admin-quit) (let* ( (cscope-list (cscope:pick-description-list cscope-id)) (cscope-label (cscope:label-of-list cscope-list)) (cscope-buffer-name (cscope:bname-from-label cscope-label)) ) (if (get-buffer cscope-buffer-name) (kill-buffer cscope-buffer-name))) ) (defun cscope-goback-and-goforth () "Return to the affiliated cscope buffer and advance the cursor by one line. The affect of this will usually be to help in stepping through references in the cscope output buffer. See also \"cscope-interpret-output-line\". After the cursor has been positioned, the optional user-supplied \"cscope-b-and-f-hook\" is run. A prefix argument causes the current window to be used for the cscope output buffer." (interactive) (if (and cscope:affiliated-buffer (get-buffer cscope:affiliated-buffer)) (if (and current-prefix-arg (not (get-buffer-window cscope:affiliated-buffer))) (switch-to-buffer cscope:affiliated-buffer) (pop-to-buffer cscope:affiliated-buffer)) (error "CSCOPE: No affiliated cscope output buffer")) (forward-line) (run-hooks 'cscope-b-and-f-hook)) (defun cscope-interpret-output-line () "Parse the line under the cursor as a cscope output reference line. Try to visit the named file and place the cursor on the mentioned line number. After the cursor has been positioned, run the optional user-supplied \"cscope-interpret-output-hook\". A prefix argument causes the current window to be used for the visited file." (interactive) (beginning-of-line) (if (not (looking-at cscope-output-line-regexp)) (error "CSCOPE: Line not understood as a cscope reference line") (let ( (cscope:filename (buffer-substring (match-beginning cscope-output-file-place) (match-end cscope-output-file-place))) (linenumb (buffer-substring (match-beginning cscope-output-line-place) (match-end cscope-output-line-place))) (function (buffer-substring (match-beginning cscope-output-func-place) (match-end cscope-output-func-place))) (find-file-not-found-hooks (list 'cscope:file-not-found)) (affiliated-buffer (buffer-name)) (cscope-id-affiliated cscope-id) ) (and (fboundp 'cscope-filename-fixxer-raw) (setq cscope:filename (funcall cscope-filename-fixxer-raw cscope:filename))) (if (not (file-name-absolute-p cscope:filename)) (setq cscope:filename (cscope:fulfill-relative-path cscope:filename))) (and (fboundp 'cscope-filename-fixxer-cooked) (setq cscope:filename (funcall cscope-filename-fixxer-cooked cscope:filename))) (if current-prefix-arg (find-file cscope:filename) (find-file-other-window cscope:filename)) (setq cscope:affiliated-buffer affiliated-buffer) (if (not cscope-id) (setq cscope-id cscope-id-affiliated)) (goto-line (string-to-int linenumb)) (message "CSCOPE: Function: %s" function) (run-hooks 'cscope-interpret-output-hook) )) ) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; only implementation stuff below here ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; A buffer-local internal variable that is used to navigate back to the ; most recent previous cscope buffer. Used by cscope-goback-and-goforth. (defvar cscope:affiliated-buffer nil) (make-variable-buffer-local 'cscope:affiliated-buffer) ; Gets a piece of menu text and strips off the last two characters, "%s" (defun cscope:get-menu-subtext (menu-item-key) (substring (cdr (assoc menu-item-key cscope:menu-text-list)) 0 -2)) ; Used to pick up buffer contents near point that match regexp. ; Works by backing up until no longer looking at something matching ; the regular expression, then finding the exact bounds by searching ; forward. (defun cscope:looking-at (regexp) (let ((fore-marker nil)) (save-excursion (if (or (looking-at regexp) (re-search-backward regexp nil t)) (progn (while (and (looking-at regexp) (not (bobp))) (backward-char 1)) (if (re-search-forward regexp nil t) (buffer-substring (match-beginning 0) (point-marker)) (identity ""))) (identity ""))))) (defun cscope:gather-c-symbol (menu-item-key) (list (read-string (cscope:get-menu-subtext menu-item-key) (cscope:looking-at cscope-c-symbol-regexp)))) (defun cscope:gather-file-name (menu-item-key) (list (read-string (cscope:get-menu-subtext menu-item-key) (cscope:looking-at cscope-filename-regexp)))) ; no default used for text string, grep/egrep patterns (defun cscope:gather-text-string (menu-item-key) (list (read-string (cscope:get-menu-subtext menu-item-key)))) ; Low-level function for passing queries to the "cscope" subprocess. ; "menu-item-key" and "item-argument" are what "cscope" is ; expecting (see the "cscope" man page). (defun cscope:query-omnibus (menu-item-key &optional item-argument) (let* (symbol do-this cscope-process) (setq symbol (if item-argument item-argument "")) (setq do-this ;; string to identify (in the cscope buffer) what's asked (format (concat (cdr (assoc menu-item-key cscope:menu-text-list)) "\n") symbol)) (setq cscope-process (cscope:pname-from-label (cscope:label-of-list (cscope:pick-description-list cscope-id)))) (if (or (eq (process-status cscope-process) 'run) (not (string-equal menu-item-key "q"))) (progn (setq cscope-process (cscope:guarantee-process do-this)) (process-send-string cscope-process (concat menu-item-key symbol "\n")) (accept-process-output cscope-process) (goto-char (point-min)) (forward-line 1) (accept-process-output) (if (looking-at "cscope: ") (forward-line 1)) (run-hooks 'cscope-query-hook) )))) ; Obviously, these are intended to match the text of menu items in ; in the fullscreen version of cscope. I've also added the "admin" ; items available under line-oriented mode. "P" is used automatically ; (and invisibly) by the interface. (defconst cscope:menu-text-list '(("0" . "Find this C symbol: %s") ("1" . "Find functions called by this function: %s") ("2" . "Find functions calling this function: %s") ("3" . "Find this text string: %s") ("6" . "Find POSIX naming violation: %s") ("5" . "Find this file: %s") ("4" . "Find files #including this file: %s") ;;("9" . "Find all functions and C++ classes") ;;("c" . "Toggle ignore/use letter case when searching") ("r" . "Rebuild the symbol database") ;;("P" . "Print relative-path prefix") ("q" . "Quit cscope")) ) ; cscope version: ;(defconst cscope:menu-text-list ; '(("0" . "Find this C symbol: %s") ; ("1" . "Find this global definition: %s") ; ("2" . "Find functions called by this function: %s") ; ("3" . "Find functions calling this function: %s") ; ("4" . "Find this text string: %s") ; ("5" . "Find this grep pattern: %s") ; ("6" . "Find this egrep pattern: %s") ; ("7" . "Find this file: %s") ; ("8" . "Find files #including this file: %s") ; ("9" . "Find all functions and C++ classes") ; ("c" . "Toggle ignore/use letter case when searching") ; ("r" . "Rebuild the symbol database") ; ("P" . "Print relative-path prefix") ; ("q" . "Quit cscope")) ;) ; mapping back and forth between label and buffer/process names (defconst cscope:bname-prefix "cscope: ") (defconst cscope:bname-prefix-length (length cscope:bname-prefix)) (defconst cscope:bname-suffix " Output") (defconst cscope:bname-suffix-length (length cscope:bname-suffix)) (defun cscope:bname-from-label (label) (concat cscope:bname-prefix label cscope:bname-suffix)) (defun cscope:label-from-bname (name) (substring (substring name 0 (- cscope:bname-suffix-length)) cscope:bname-prefix-length)) (defconst cscope:pname-prefix "cscope: ") (defconst cscope:pname-prefix-length (length cscope:pname-prefix)) (defconst cscope:pname-suffix " Process") (defconst cscope:pname-suffix-length (length cscope:pname-suffix)) (defun cscope:pname-from-label (label) (concat cscope:pname-prefix label cscope:pname-suffix)) (defun cscope:label-from-pname (name) (substring (substring name 0 (- cscope:pname-suffix-length)) cscope:pname-prefix-length)) ; if the appropriate cscope subprocess is not already running, start it ; up, initialize buffers, etc; if it is running, just do the buffer biz (defun cscope:guarantee-process (do-this) (let* ( (cscope-list (cscope:pick-description-list cscope-id)) (cscope-label (cscope:label-of-list cscope-list)) (cscope-buffer-name (cscope:bname-from-label cscope-label)) (cscope-process-name (cscope:pname-from-label cscope-label)) (cscope-process nil) (cd-place (if (cscope:cdplace-of-list cscope-list) (cscope:cdplace-of-list cscope-list) default-directory)) ) (if (eq (process-status cscope-process-name) 'run) (save-excursion (set-buffer cscope-buffer-name) (erase-buffer)) (message "CSCOPE: Starting process for %s ..." cscope-label) (and (get-buffer cscope-buffer-name) (kill-buffer cscope-buffer-name)) (setq cscope-process (let ( ;; sje was a pipe (nil) now a pty (t) ;; Sun 16 Nov 97 (process-connection-type t) ; use a pipe (default-directory cd-place)) (apply 'start-process cscope-process-name cscope-buffer-name (cscope:command-of-list cscope-list)))) (process-kill-without-query cscope-process) (cscope:figure-out-path-prefix cscope-label cscope-buffer-name cscope-process) (message "CSCOPE: Starting process for %s ... started" cscope-label) (run-hooks 'cscope-start-process-hook) ) (if (and current-prefix-arg (not (get-buffer-window cscope-buffer-name))) (switch-to-buffer cscope-buffer-name) (pop-to-buffer cscope-buffer-name)) (setq cscope-process (get-process cscope-process-name)) (if (not cscope-id) (setq cscope-id cscope-label)) (use-local-map cscope-keymap) (insert do-this) (set-marker (process-mark cscope-process) (point-max)) (identity cscope-process) )) ; keep a list of path prefixes that can be discovered by asking cscope (defvar cscope:path-prefix-table nil) (defun cscope:figure-out-path-prefix (cscope-label cscope-buffer-name cscope-process) (set-buffer cscope-buffer-name) (goto-char (point-min)) (while (and (eq (process-status cscope-process) 'run) (not (re-search-forward "^>>" nil t))) (goto-char (point-min)) (accept-process-output)) (if (not (eq (process-status cscope-process) 'run)) (message "CSCOPE: Dead process for %s" cscope-label) (erase-buffer) (process-send-string cscope-process "P\n") (while (and (eq (process-status cscope-process) 'run) (not (re-search-forward "^>>" nil t))) (goto-char (point-min)) (accept-process-output)) (goto-char (point-min)) (if (not (looking-at ".*cscope.* unknown ")) ;; sometimes no P support (progn (end-of-line) (let* ( (path-prefix (buffer-substring (point-min) (point))) (list-item (if cscope:path-prefix-table (assoc cscope-label cscope:path-prefix-table) nil)) ) (if list-item (setcdr list-item path-prefix) (setq cscope:path-prefix-table (cons '(cscope-label . path-prefix) cscope:path-prefix-table))) ))) ) (erase-buffer) ) (defun cscope:pick-description-list (cscope-id) (if (and cscope-master-info-table (assoc cscope-id cscope-master-info-table)) (assoc cscope-id cscope-master-info-table) (identity cscope-master-info-default))) ; catch the file-not-found situation so that a new empty file isn't just ; opened up as a routine matter; instead, give a message (defun cscope:file-not-found () (if cscope-file-not-found-hook (run-hooks 'cscope-file-not-found-hook) (kill-buffer (get-file-buffer cscope:filename)) (error "CSCOPE: Can't find file %s" cscope:filename))) ; convert cscope's relative pathnames into absolute pathnames; ; try computed path prefix, user-specified path prefix, and user-specified ; "cd place" (defun cscope:fulfill-relative-path (filename) (let* ( (list-item (if cscope:path-prefix-table (assoc cscope-id cscope:path-prefix-table) nil)) (prefix (if list-item (cdr list-item) nil)) (cscope-list (cscope:pick-description-list cscope-id)) ) (if (not prefix) (setq prefix (cscope:pathprefix-of-list cscope-list))) (if (not prefix) (setq prefix (cscope:cdplace-of-list cscope-list))) (if prefix (format "%s/%s" prefix filename) (identity filename)) ) ) (provide 'cscope) ;;; cscope.el ends here