home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / languages / elisp / interfaces / cscope.el < prev    next >
Encoding:
Text File  |  1991-11-11  |  39.5 KB  |  924 lines

  1. ; From billc@pegasus.ATT.COM Mon Nov 11 20:53:08 1991
  2. ; Xref: cbnewsh comp.emacs:7861 gnu.emacs.sources:558
  3. ; Newsgroups: comp.emacs,gnu.emacs.sources
  4. ; Path: cbnewsh!hos1cad!billc
  5. ; From: billc@pegasus.ATT.COM (Bill Carpenter)
  6. ; Subject: GNUemacs-to-cscope interface, cscope.el
  7. ; Organization: AT&T Bell Laboratories
  8. ; Date: Tue, 12 Nov 1991 01:51:45 GMT
  9. ; Message-ID: <1991Nov12.015145.9840@cbnewsh.cb.att.com>
  10. ; Sender: bill@cbnewsh.cb.att.com (william.j.carpenter)
  11. ; Lines: 909
  12.  
  13. ; This is an interface from GNUemacs to Joe Steffen's "cscope" C browser.  
  14. ; With this code, you can do things like put your cursor on some C
  15. ; symbol, hit a couple keys and be transported anyplace special that
  16. ; cscope knows about.  See the variable cscope-blurb for more general info.
  17. ;
  18. ; If you use this, I am interested in hearing from you how it went,
  19. ; especially if you find bugs or if you use cscope in some way that
  20. ; this interface doesn't support (or doesn't support very well).
  21. ;
  22. ;  Bill                      William_J_Carpenter@ATT.COM        or
  23. ;  (908) 576-2932            attmail!bill   or   att!pegasus!billc
  24. ;  AT&T Bell Labs / AT&T EasyLink Services               LZ 1E-207
  25.  
  26. ;;cscope.el
  27. ;;
  28. ;;;
  29. ;;; LCD Archive Entry:
  30. ;;; cscope|Bill Carpenter|William_J_Carpenter@ATT.COM
  31. ;;; |Interface to cscope browser
  32. ;;; |91-11-11|1|~/interfaces/cscope.el.Z|
  33. ;;;
  34. ;;; patchlevel 0,   13-Oct-91  (beta)
  35. ;;; patchlevel 1,   11-Nov-91  first general release
  36. ;;;
  37. ;;; As far as I'm concerned, anyone can do anything they want with
  38. ;;; this specific piece of code.  No warranty or promise of support is
  39. ;;; offered.  I am interested in hearing reports of bugs or interesting
  40. ;;; uses.  Suggestions for interesting enhancements are welcome.
  41.  
  42. ;;; My thanks to the beta testers.  I am especially appreciative of
  43. ;;; the helpful feedback received about earlier versions of this from
  44. ;;; Mike Balenger and Neal McBurnett.
  45.  
  46. (defconst cscope-version "patchlevel 1, 11 Nov 91")
  47.  
  48. (defvar cscope-bindings-2deep nil
  49.   "*If non-nil, then two character bindings are applied when 
  50. \"cscope-bind-keys\" is called.  The two character bindings are mostly
  51. of the form \"C-c letter\".  The reason they are optional is that there
  52. is an elisp coding convention which suggests that those kinds of bindings
  53. should be reserved for users.  The binding of \"C-c C-c\" is not controlled
  54. by this user option variable; it is always applied.")
  55.  
  56. (defvar cscope-bindings-3deep t
  57.   "*If non-nil, then three character bindings are applied when
  58. \"cscope-bind-keys\" is called.  The three character bindings are mostly
  59. of the form \"C-c C-s letter\".")
  60.  
  61. (defvar cscope-bind-keys-hook nil
  62.   "At the end of the function \"cscope-find-keys\", this hook is run.
  63. This provides an opportunity for custom keybinding schemes as well as any 
  64. other buffer-specific set-up.  In cscope output buffers, this hook is run
  65. before the extra bindings are applied; however, since those extra bindings
  66. are all in \"cscope-keymap\", they can be modified directly by the user
  67. to affect all cscope output buffers.")
  68.  
  69. (defvar cscope-quit-hook nil
  70.   "Called after a cscope subprocess is told to exit.  If called as part of
  71. a command that also kills the buffer, the hook is run before the buffer is
  72. killed.")
  73.  
  74. (defvar cscope-b-and-f-hook nil
  75.   "Run after the user bounces back to the cscope output buffer from a
  76. source file.  This hook is run after the cursor has been positoned.  It gives
  77. the user an opportunity to use some other cursor positioning strategy instead
  78. of just advancing to the next line.")
  79.  
  80. (defvar cscope-interpret-output-hook nil
  81.   "Run after the user moves from a cscope output line to the referenced
  82. source file.  This hook is run after the cursor has been positoned.  It gives
  83. the user an opportunity to use some other cursor positioning strategy.")
  84.  
  85. (defvar cscope-query-hook nil
  86.   "Run after a query has been made of the cscope subprocess.  Normally, the
  87. cscope interface tries to position the cursor at the first cscope
  88. result line, but it is possible for it to miss.  This hook allows an
  89. alternate cursor positioning strategy or any other after-the-query
  90. processing.  For example, if you felt like it, you could \"pre-visit\"
  91. all the files mentioned in output lines.  More usefully, you might
  92. like to automatically visit a referenced source file
  93. line if there is only one output line from cscope.")
  94.  
  95. (defvar cscope-file-not-found-hook nil
  96.   "If defined, this behaves slightly differently than a standard emacs
  97. hook function.  It is run instead of (not in addition to) the normal
  98. action taken if some referenced source file can't be found.  Normally,
  99. (if this hook is not defined) the cscope interface will signal an
  100. error and give up looking.")
  101.  
  102. (defvar cscope-filename-fixxer-raw nil
  103.   "If defined as a function, called to generate a filename.  The single
  104. argument is a raw filename reference as taken from a cscope output
  105. buffer.  The expected return value is something that the cscope
  106. interface will try to resolve into a full pathname (using mechanisms
  107. desribed elsewhere).")
  108.  
  109. (defvar cscope-filename-fixxer-cooked nil
  110.   "If defined as a function, called to generate a filename.  The
  111. single argument is a cooked filename reference, meaning that the
  112. cscope interface has already tried to resolve it into a full pathname
  113. (using mechanisms described elsewhere).  Since the resolution doesn't
  114. always succeed, the argument might not be a full pathname.  The
  115. expected return value is something that the cscope interface will try
  116. to visit with \"find-file\".")
  117.  
  118. (defvar cscope-blurb nil
  119.   "This is an interface from GNUemacs to the line-oriented mode of Joe
  120. Steffen's cscope, a C code browser (cscope itself is available from
  121. the AT&T Toolchest).  The interface includes provisions for having
  122. multiple concurrent unrelated cscope sessions.  For casual use,
  123. arrange for this file to be loaded and call the function
  124. \"cscope-bind-keys\".  See the documentation for \"cscope-bind-keys\"
  125. for more information about that.
  126.  
  127. If you are inclined to have multiple cscope sessions, possibly with different
  128. invocation command lines or using pre-built databases, then see the
  129. documentation for cscope-master-info-table and cscope-master-info-default.
  130.  
  131. The general method of using this is to arrange for the cscope-related
  132. bindings to be made, place the cursor over some symbol or filename in
  133. question, and invoke the appropriate cscope function.  This will invoke
  134. a cscope subprocess (if it's not already running) and perform the query.
  135. The results of the query are presented in a cscope output buffer.  The
  136. user can place the cursor over a cscope reference line and type \"C-c C-c\"
  137. to move to the referenced location.  After that, the user can type
  138. \"C-c C-c\" again and move back to the cscope output buffer, automatically
  139. advancing the cursor to the next line.  Functions that cause other buffers
  140. to be displayed generally pop them up in another window.  If those functions
  141. are called with prefix arguments, then the summoned buffer is put in the
  142. currently selected window.
  143.  
  144. A good way to arrange for this file to be loaded is via c-mode-hook.  This
  145. file \"provides\" cscope, so you can use \"require\" directives and/or
  146. autoloading.  Here's a example:
  147.  
  148.     (autoload 'cscope-bind-keys \"cscope\" nil t)
  149.  
  150.     (defun wjc:c-mode-hook () \"my C mode hook\"
  151.         ;; only bother doing the bindings first time ... they'll stick
  152.         (or (where-is-internal 'cscope-find-c-symbol (current-local-map))
  153.             (cscope-bind-keys))
  154.         ;; (and (boundp 'cscope-blurb) (makunbound 'cscope-blurb))
  155.         (local-set-key \"\\M-?\" 'cscope-find-c-symbol))
  156.  
  157.     (setq c-mode-hook 'wjc:c-mode-hook)
  158.  
  159. If you've seen the information in the description of this user option
  160. variable enough times, you can let emacs reclaim the string space by
  161. doing (makunbound 'cscope-blurb) after the cscope interface is loaded 
  162. (shown as a commented line in the above example).  Even if you don't
  163. have handy the source file, cscope.el, you'll still be able to read the
  164. docstrings in cscope.elc.")
  165.  
  166. (defvar cscope-master-info-table nil
  167.   "*A list-of-lists telling how to run cscope for a given buffer.
  168. If you're not doing anything fancy with the cscope interface, like browsing
  169. multiple databases concurrently, then you probably don't need to set this.
  170. Each item in \"cscope-master-info-table\" is a list.  Trailing nil items from
  171. the sublists may be omitted.
  172.  
  173. The first item in each sublist is a string which acts as the key for that
  174. sublist.  If the value of the buffer-local variable \"cscope-id\" matches
  175. the key, then that sublist is used to decide how to run cscope for that
  176. buffer.  If no sublist in the entire table matches \"cscope-id\", then
  177. \"cscope-master-info-default\" is used.
  178.  
  179. The second item in each sublist is itself a list.  It's a list of strings
  180. which comprise the command line and arguments for invoking cscope.  See
  181. the cscope man page for valid command line arguments.  Don't forget to make
  182. sure that cscope and/or user-specified cscope commands are available via
  183. the PATH environment variable.
  184.  
  185. The third item in each sublist is an optional \"cd place\".  If a non-nil
  186. string, the current directory will be temporarily changed to the directory
  187. named while cscope is being invoked (ie, while the cscope subprocess is
  188. being spawned).  After cscope is invoked, the current directory is returned
  189. to whatever it was before.
  190.  
  191. The fourth item in each sublist is a user-specified path prefix.  A
  192. cscope database might only know relative pathnames.  Some versions of
  193. cscope can be queried for the path prefix to use with relative
  194. pathnames, but this does not work with all versions.  If cscope tells
  195. emacs about a filename that is a relative pathname, the automatically
  196. known path prefix is prepended.  If there is no automatically known
  197. path prefix, the user-specified path prefix is used.  If there is no
  198. user-specified path prefix, the \"cd place\" is used.  Otherwise, the
  199. unprefixed relative pathname is used.
  200.  
  201. Here's an example of a personal setting for this variable:
  202.  
  203.     (setq cscope-master-info-table
  204.       '(
  205.         (\"projA\" (\"cscope\" \"-l\" \"-d\" \"-f\" \"/projA/src/cscope.out\"))
  206.         (\"projB\" (\"cscope\" \"-l\" \"-d\" \"-f\" \"/projB/src/cscope.out\"))
  207.       ))
  208.  
  209. The example uses separate pre-built cscope databases for projects
  210. \"projA\" and \"projB\".  The last two items in the sublists are nil
  211. (because they're not specified), which is a good clue that the
  212. databases were built knowing full pathnames.  For buffers that are not
  213. \"projA\" or \"projB\", the default cscope invocation will be used.")
  214.  
  215. (defvar cscope-master-info-default '("CSCOPE" ("cscope" "-l") nil nil)
  216.   "*When a search of \"cscope-master-info-table\" is done and no match
  217. is found, the list specified by this variable is returned instead.  See
  218. the documentation for \"cscope-master-info-table\" for an explanation of
  219. the items in the list.")
  220.  
  221. (defvar cscope-id nil
  222.   "*Used as a key into \"cscope-master-info-table\".  This is a buffer-local
  223. variable and could be set manually or by some mode-specific hook function.
  224. If this variable is not explicitly set, it will generally result in the
  225. use of \"cscope-master-info-default\".  The value of \"cscope-id\"
  226. follows from buffer to buffer, but will not override any previously
  227. set values.  That is, if a given buffer has a cscope-id of \"foo\", a
  228. cscope output buffer for a cscope process started from that buffer
  229. will also get a cscope-id of \"foo\".  Any source files newly visited
  230. as a result of cscope queries from that cscope process will also get a
  231. cscope-id of \"foo\".  Users can overcome that by explicitly setting
  232. cscope-id via some hook or other means.  \"cscope-id\" is
  233. buffer-local, so if you kill-all-local-variables, the value will be
  234. lost.")
  235.  
  236. (make-variable-buffer-local 'cscope-id)
  237.  
  238. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  239. ; most users need not explore below here except to read function
  240. ; documentation strings; you can just as well describe-function
  241. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  242.  
  243. (defvar cscope-output-line-regexp
  244.   "\\s-*\\(\\S-+\\)\\s-+\\(\\S-+\\)\\s-+\\([0-9]+\\)"
  245. "*This regular expression is used to recognize valid reference lines of 
  246. output from the output of the line-oriented mode of cscope.  It must include
  247. subexpressions which obtain the filename, function name, and line number.")
  248.  
  249. (defvar cscope-output-file-place 1
  250.   "*Position number of the \"cscope-output-line-regexp\" subexpression
  251. which locates the filename.")
  252.  
  253. (defvar cscope-output-func-place 2
  254.   "*Position number of the \"cscope-output-line-regexp\" subexpression
  255. which locates the function name.")
  256.  
  257. (defvar cscope-output-line-place 3
  258.   "*Position number of the \"cscope-output-line-regexp\" subexpression
  259. which locates the line number.")
  260.  
  261. (defvar cscope-c-symbol-regexp "[a-zA-Z0-9_]+"
  262.   "*A regular expression specifying a legitimate C symbol.  Used for
  263. finding a default symbol for minibuffer prompting.  User input need
  264. not conform to this regular expression.")
  265.  
  266. (defvar cscope-filename-regexp "[a-zA-Z0-9_.-]+"
  267.   "*A regular expression specifying a legitimate file name.  Used for
  268. finding a default filename for minibuffer prompting.  User input need
  269. not conform to this regular expression.")
  270.  
  271. ; macros for pulling items out of sublists from cscope-master-info-table
  272. (defmacro cscope:label-of-list      (cl) (list 'nth 0 cl))
  273. (defmacro cscope:command-of-list    (cl) (list 'nth 1 cl))
  274. (defmacro cscope:cdplace-of-list    (cl) (list 'nth 2 cl))
  275. (defmacro cscope:pathprefix-of-list (cl) (list 'nth 3 cl))
  276.  
  277. (defun cscope-bind-keys ()
  278.   "Establish the key bindings for cscope queries and interactions.
  279. A reasonable thing to do is to call this function from \"c-mode-hook\".
  280. However, if you use a minor mode which changes the keymap, you may
  281. have to take extra steps.  For example, \"view-mode\" installs its own
  282. keymap and is often called via \"find-file-hooks\".  For that
  283. particular case, it may be helpful to have a line something like this
  284. automatically invoked after \"view-mode\" has been installed:
  285.  
  286.       (if (eq major-mode 'c-mode) (cscope-bind-keys))
  287.  
  288. Keys bound by invoking this function can be listed by going to a
  289. buffer where the bindings are active and doing \\[describe-bindings].
  290. They usually begin with a C-c C-s prefix.  If \"cscope-bindings-2deep\"
  291. is non-nil, then you will see bindings of the form \"C-c letter\".  If
  292. \"cscope-bindings-3deep\" is non-nil (the default), you will see
  293. bindings of the form \"C-c C-s letter\".  These settings are
  294. independent of one another, and by default the three character
  295. bindings are provided and the two character bindings are not.  The
  296. bindings are put in place by modifying whatever keymaps happen to be in
  297. effect whenever you invoke this function.  For most users, this will mean
  298. it's a more or less global change (e.g., to \"c-mode-map\").
  299.  
  300. In any case, the binding of \"C-c C-c\" is provided.  After the bindings
  301. have been made, the optional user-supplied \"cscope-bind-keys-hook\" is run.
  302.  
  303. In cscope output buffers, there are additional single character
  304. bindings (not controlled by any user option variable).  Further, the
  305. two and/or three character bindings are provided, depending on the
  306. values of the \"cscope-bindings-2deep\" and \"cscope-bindings-3deep\"
  307. at the time the cscope interface is first loaded.  A different binding is
  308. given to \"C-c C-c\" in cscope output buffers.
  309.  
  310. Within each set of bindings, more than one binding is made for some
  311. functions for convenience.  Use \\[describe-bindings] to get a
  312. complete list.  The intent of the alternate bindings of
  313. cscope-interpret-output-line and cscope-goback-and-goforth in
  314. different buffer types is so that an interested user can step through
  315. references in a cscope output buffer by repeatedly typing the same
  316. keys."
  317.   (interactive)
  318.   (if cscope-bindings-2deep (cscope-bind-keys-2deep))
  319.   (if cscope-bindings-3deep (cscope-bind-keys-3deep))
  320.   (local-set-key "\C-c\C-c" 'cscope-goback-and-goforth)
  321.   (run-hooks 'cscope-bind-keys-hook)
  322. )
  323.  
  324. (defun cscope-bind-keys-2deep ()
  325.   (interactive)
  326.   "Apply two character cscope bindings to the currently active keymap.
  327. The bindings are of the form \"C-c letter\"  See variable
  328. \"cscope-bindings-2deep\"."
  329.   (local-set-key "\C-cc" 'cscope-find-c-symbol)
  330.   (local-set-key "\C-cC" 'cscope-find-c-symbol)
  331.   ;; (local-set-key "\C-c\C-c" 'cscope-find-c-symbol)
  332.  
  333.   (local-set-key "\C-cd" 'cscope-find-global-definition)
  334.   (local-set-key "\C-cD" 'cscope-find-global-definition)
  335.   (local-set-key "\C-c\C-d" 'cscope-find-global-definition)
  336.  
  337.   (local-set-key "\C-cv" 'cscope-find-functions-called)
  338.   (local-set-key "\C-cV" 'cscope-find-functions-called)
  339.   (local-set-key "\C-c\C-v" 'cscope-find-functions-called)
  340.  
  341.   (local-set-key "\C-c^" 'cscope-find-functions-calling)
  342.   (local-set-key "\C-c6" 'cscope-find-functions-calling)
  343.  
  344.   (local-set-key "\C-ct" 'cscope-find-text-string)
  345.   (local-set-key "\C-cT" 'cscope-find-text-string)
  346.   (local-set-key "\C-c\C-t" 'cscope-find-text-string)
  347.  
  348.   (local-set-key "\C-cg" 'cscope-find-grep-pattern)
  349.   (local-set-key "\C-cG" 'cscope-find-grep-pattern)
  350.   (local-set-key "\C-c\C-g" 'cscope-find-grep-pattern)
  351.  
  352.   (local-set-key "\C-ce" 'cscope-find-egrep-pattern)
  353.   (local-set-key "\C-cE" 'cscope-find-egrep-pattern)
  354.   (local-set-key "\C-c\C-e" 'cscope-find-egrep-pattern)
  355.  
  356.   (local-set-key "\C-cf" 'cscope-find-file)
  357.   (local-set-key "\C-cF" 'cscope-find-file)
  358.   (local-set-key "\C-c\C-f" 'cscope-find-file)
  359.  
  360.   (local-set-key "\C-ci" 'cscope-find-files-including)
  361.   (local-set-key "\C-cI" 'cscope-find-files-including)
  362.   (local-set-key "\C-c\C-i" 'cscope-find-files-including)
  363.  
  364.   (local-set-key "\C-c#" 'cscope-find-files-including)
  365.   (local-set-key "\C-c3" 'cscope-find-files-including)
  366.   (local-set-key "\C-c*" 'cscope-find-all)
  367.   (local-set-key "\C-c8" 'cscope-find-all)
  368.  
  369.   (local-set-key "\C-ca" 'cscope-admin-toggle-case)
  370.   (local-set-key "\C-cA" 'cscope-admin-toggle-case)
  371.   (local-set-key "\C-c\C-a" 'cscope-admin-toggle-case)
  372.  
  373.   (local-set-key "\C-cr" 'cscope-admin-rebuild-db)
  374.   (local-set-key "\C-cR" 'cscope-admin-rebuild-db)
  375.   (local-set-key "\C-c\C-r" 'cscope-admin-rebuild-db)
  376.  
  377.   (local-set-key "\C-cp" 'cscope-query-path-prefix)
  378.   (local-set-key "\C-cP" 'cscope-query-path-prefix)
  379.   (local-set-key "\C-c\C-p" 'cscope-query-path-prefix)
  380.  
  381.   (local-set-key "\C-cx" 'cscope-admin-quit)
  382.   (local-set-key "\C-cX" 'cscope-admin-quit)
  383.   (local-set-key "\C-c\C-x" 'cscope-admin-quit)
  384.  
  385.   (local-set-key "\C-cq" 'cscope-admin-quit-and-kill-buffer)
  386.   (local-set-key "\C-cQ" 'cscope-admin-quit-and-kill-buffer)
  387.   (local-set-key "\C-c\C-q" 'cscope-admin-quit-and-kill-buffer)
  388. )
  389.  
  390. (defun cscope-bind-keys-3deep ()
  391.   (interactive)
  392.   "Apply three character cscope bindings to the currently active keymap.
  393. The bindings are of the form \"C-c C-s letter\"  See variable
  394. \"cscope-bindings-3deep\"."
  395.   (local-set-key "\C-c\C-sc" 'cscope-find-c-symbol)
  396.   (local-set-key "\C-c\C-sC" 'cscope-find-c-symbol)
  397.   (local-set-key "\C-c\C-s\C-c" 'cscope-find-c-symbol)
  398.  
  399.   (local-set-key "\C-c\C-sd" 'cscope-find-global-definition)
  400.   (local-set-key "\C-c\C-sD" 'cscope-find-global-definition)
  401.   (local-set-key "\C-c\C-s\C-d" 'cscope-find-global-definition)
  402.  
  403.   (local-set-key "\C-c\C-sv" 'cscope-find-functions-called)
  404.   (local-set-key "\C-c\C-sV" 'cscope-find-functions-called)
  405.   (local-set-key "\C-c\C-s\C-v" 'cscope-find-functions-called)
  406.  
  407.   (local-set-key "\C-c\C-s^" 'cscope-find-functions-calling)
  408.   (local-set-key "\C-c\C-s6" 'cscope-find-functions-calling)
  409.  
  410.   (local-set-key "\C-c\C-st" 'cscope-find-text-string)
  411.   (local-set-key "\C-c\C-sT" 'cscope-find-text-string)
  412.   (local-set-key "\C-c\C-s\C-t" 'cscope-find-text-string)
  413.  
  414.   (local-set-key "\C-c\C-sg" 'cscope-find-grep-pattern)
  415.   (local-set-key "\C-c\C-sG" 'cscope-find-grep-pattern)
  416.   (local-set-key "\C-c\C-s\C-g" 'cscope-find-grep-pattern)
  417.  
  418.   (local-set-key "\C-c\C-se" 'cscope-find-egrep-pattern)
  419.   (local-set-key "\C-c\C-sE" 'cscope-find-egrep-pattern)
  420.   (local-set-key "\C-c\C-s\C-e" 'cscope-find-egrep-pattern)
  421.  
  422.   (local-set-key "\C-c\C-sf" 'cscope-find-file)
  423.   (local-set-key "\C-c\C-sF" 'cscope-find-file)
  424.   (local-set-key "\C-c\C-s\C-f" 'cscope-find-file)
  425.  
  426.   (local-set-key "\C-c\C-si" 'cscope-find-files-including)
  427.   (local-set-key "\C-c\C-sI" 'cscope-find-files-including)
  428.   (local-set-key "\C-c\C-s\C-i" 'cscope-find-files-including)
  429.  
  430.   (local-set-key "\C-c\C-s#" 'cscope-find-files-including)
  431.   (local-set-key "\C-c\C-s3" 'cscope-find-files-including)
  432.   (local-set-key "\C-c\C-s*" 'cscope-find-all)
  433.   (local-set-key "\C-c\C-s8" 'cscope-find-all)
  434.  
  435.   (local-set-key "\C-c\C-sa" 'cscope-admin-toggle-case)
  436.   (local-set-key "\C-c\C-sA" 'cscope-admin-toggle-case)
  437.   (local-set-key "\C-c\C-s\C-a" 'cscope-admin-toggle-case)
  438.  
  439.   (local-set-key "\C-c\C-sr" 'cscope-admin-rebuild-db)
  440.   (local-set-key "\C-c\C-sR" 'cscope-admin-rebuild-db)
  441.   (local-set-key "\C-c\C-s\C-r" 'cscope-admin-rebuild-db)
  442.  
  443.   (local-set-key "\C-c\C-sp" 'cscope-query-path-prefix)
  444.   (local-set-key "\C-c\C-sP" 'cscope-query-path-prefix)
  445.   (local-set-key "\C-c\C-s\C-p" 'cscope-query-path-prefix)
  446.  
  447.   (local-set-key "\C-c\C-sx" 'cscope-admin-quit)
  448.   (local-set-key "\C-c\C-sX" 'cscope-admin-quit)
  449.   (local-set-key "\C-c\C-s\C-x" 'cscope-admin-quit)
  450.  
  451.   (local-set-key "\C-c\C-sq" 'cscope-admin-quit-and-kill-buffer)
  452.   (local-set-key "\C-c\C-sQ" 'cscope-admin-quit-and-kill-buffer)
  453.   (local-set-key "\C-c\C-s\C-q" 'cscope-admin-quit-and-kill-buffer)
  454. )
  455.  
  456. (if (not (boundp 'cscope-keymap))
  457.     (progn
  458.       (setq cscope-keymap (copy-keymap text-mode-map))
  459.       (let ((real-keymap (current-local-map)))
  460.         (use-local-map cscope-keymap)
  461.         (cscope-bind-keys)
  462.         (use-local-map real-keymap))
  463.  
  464.       (define-key cscope-keymap "c" 'cscope-find-c-symbol)
  465.       (define-key cscope-keymap "C" 'cscope-find-c-symbol)
  466.       
  467.       (define-key cscope-keymap "d" 'cscope-find-global-definition)
  468.       (define-key cscope-keymap "D" 'cscope-find-global-definition)
  469.       
  470.       (define-key cscope-keymap "v" 'cscope-find-functions-called)
  471.       (define-key cscope-keymap "V" 'cscope-find-functions-called)
  472.       
  473.       (define-key cscope-keymap "^" 'cscope-find-functions-calling)
  474.       
  475.       (define-key cscope-keymap "t" 'cscope-find-text-string)
  476.       (define-key cscope-keymap "T" 'cscope-find-text-string)
  477.       
  478.       (define-key cscope-keymap "g" 'cscope-find-grep-pattern)
  479.       (define-key cscope-keymap "G" 'cscope-find-grep-pattern)
  480.       
  481.       (define-key cscope-keymap "e" 'cscope-find-egrep-pattern)
  482.       (define-key cscope-keymap "E" 'cscope-find-egrep-pattern)
  483.       
  484.       (define-key cscope-keymap "f" 'cscope-find-file)
  485.       (define-key cscope-keymap "F" 'cscope-find-file)
  486.       
  487.       (define-key cscope-keymap "i" 'cscope-find-files-including)
  488.       (define-key cscope-keymap "I" 'cscope-find-files-including)
  489.       
  490.       (define-key cscope-keymap "#" 'cscope-find-files-including)
  491.       (define-key cscope-keymap "*" 'cscope-find-all)
  492.       
  493.       (define-key cscope-keymap "a" 'cscope-admin-toggle-case)
  494.       (define-key cscope-keymap "A" 'cscope-admin-toggle-case)
  495.       
  496.       (define-key cscope-keymap "r" 'cscope-admin-rebuild-db)
  497.       (define-key cscope-keymap "R" 'cscope-admin-rebuild-db)
  498.       
  499.       (define-key cscope-keymap "p" 'cscope-query-path-prefix)
  500.       (define-key cscope-keymap "P" 'cscope-query-path-prefix)
  501.       
  502.       (define-key cscope-keymap "x" 'cscope-admin-quit)
  503.       (define-key cscope-keymap "X" 'cscope-admin-quit)
  504.       
  505.       (define-key cscope-keymap "q" 'cscope-admin-quit-and-kill-buffer)
  506.       (define-key cscope-keymap "Q" 'cscope-admin-quit-and-kill-buffer)
  507.  
  508.       (define-key cscope-keymap "\C-c\C-c" 'cscope-interpret-output-line)
  509.       ))
  510.   
  511.  
  512. (defun cscope-find-c-symbol (symbol)
  513.   "Query cscope for the whereabouts of the given symbol.
  514. When called interactively, the user is prompted for the symbol name,
  515. with a symbol near point being the default.  A prefix argument causes
  516. the current window to be used for the output."
  517.   (interactive (cscope:gather-c-symbol "0"))
  518.   (cscope:query-omnibus "0" symbol))
  519.  
  520. (defun cscope-find-global-definition (symbol)
  521.   "Query cscope for the global definition of the given symbol.
  522. When called interactively, the user is prompted for the symbol name,
  523. with a symbol near point being the default.  A prefix argument causes
  524. the current window to be used for the output."
  525.   (interactive (cscope:gather-c-symbol "1"))
  526.   (cscope:query-omnibus "1" symbol))
  527.  
  528. (defun cscope-find-functions-called (symbol)
  529.   "Query cscope for the names of functions called by a function.
  530. When called interactively, the user is prompted for the function name,
  531. with a symbol near point being the default.  A prefix argument causes
  532. the current window to be used for the output."
  533.   (interactive (cscope:gather-c-symbol "2"))
  534.   (cscope:query-omnibus "2" symbol))
  535.  
  536. (defun cscope-find-functions-calling (symbol)
  537.   "Query cscope for the names of functions calling a function.
  538. When called interactively, the user is prompted for the function name,
  539. with a symbol near point being the default.  A prefix argument causes
  540. the current window to be used for the output."
  541.   (interactive (cscope:gather-c-symbol "3"))
  542.   (cscope:query-omnibus "3" symbol))
  543.  
  544. (defun cscope-find-text-string (symbol)
  545.   "Query cscope for the whereabouts of the given text string.
  546. When called interactively, the user is prompted for the string.  A
  547. prefix argument causes the current window to be used for the output."
  548.   (interactive (cscope:gather-text-string "4"))
  549.   (cscope:query-omnibus "4" symbol))
  550.  
  551. (defun cscope-find-grep-pattern (symbol)
  552.   "Query cscope for the whereabouts of the given grep pattern.  When
  553. called interactively, the user is prompted for the pattern.  (The
  554. line-oriented mode of cscope does not support changing occurrences of
  555. the given pattern; the full-screen version of cscope does.)  A prefix
  556. argument causes the current window to be used for the output."
  557.   (interactive (cscope:gather-text-string "5"))
  558.   (cscope:query-omnibus "5" symbol))
  559.  
  560. (defun cscope-find-egrep-pattern (symbol)
  561.   "Query cscope for the whereabouts of the given egrep pattern.  When
  562. called interactively, the user is prompted for the pattern.  A prefix
  563. argument causes the current window to be used for the output."
  564.   (interactive (cscope:gather-text-string "6"))
  565.   (cscope:query-omnibus "6" symbol))
  566.  
  567. (defun cscope-find-file (symbol)
  568.   "Query cscope for the whereabouts of the given file.
  569. When called interactively, the user is prompted for the file name,
  570. with a symbol near point being the default.  A prefix argument causes
  571. the current window to be used for the output."
  572.   (interactive (cscope:gather-file-name "7"))
  573.   (cscope:query-omnibus "7" symbol))
  574.  
  575. (defun cscope-find-files-including (symbol)
  576.   "Query cscope for the files including a given file.
  577. When called interactively, the user is prompted for the file name,
  578. with a symbol near point being the default.  A prefix argument causes
  579. the current window to be used for the output."
  580.   (interactive (cscope:gather-file-name "8"))
  581.   (cscope:query-omnibus "8" symbol))
  582.  
  583. (defun cscope-find-all (&rest symbol)
  584.   "Query cscope for the definitions of all functions and C++ classes.
  585. Any arguments to this function are ignored.  A prefix argument causes
  586. the current window to be used for the output."
  587.   (interactive)
  588.   (cscope:query-omnibus "9" "fake"))
  589.  
  590. (defun cscope-admin-toggle-case (&rest symbol)
  591.   "Toggle case-folding for subsequent cscope searches.  Since
  592. case-folding can also be affected by a command line option when cscope
  593. is invoked, it's up to the user to keep track of the state of the
  594. toggle.  Any arguments to this function are ignored.  A prefix
  595. argument causes the current window to be used for the output."
  596.   (interactive)
  597.   (cscope:query-omnibus "c"))
  598.  
  599. (defun cscope-admin-rebuild-db (&rest symbol)
  600.   "Tell the cscope subprocess to rebuild its database.
  601. Any arguments to this function are ignored.  A prefix argument causes
  602. the current window to be used for the output."
  603.   (interactive)
  604.   (cscope:query-omnibus "r"))
  605.  
  606. (defun cscope-query-path-prefix (&rest symbol)
  607.   "Query cscope for the relative filename path prefix.  Not all
  608. versions of cscope support this feature; if yours doesn't, it will be
  609. obvious from what you see in the cscope output buffer after running
  610. this command.  Any arguments to this function are ignored.  A prefix
  611. argument causes the current window to be used for the output."
  612.   (interactive)
  613.   (cscope:query-omnibus "P"))
  614.  
  615. (defun cscope-admin-quit (&rest symbol)
  616.   "Tell the cscope subprocess to terminate.
  617. Any arguments to this function are ignored.  Afterwards, run the 
  618. optional user-supplied \"cscope-quit-hook\".  A prefix argument causes
  619. the current window to be used for the output."
  620.   (interactive)
  621.   (prog1 (cscope:query-omnibus "q")
  622.     (run-hooks 'cscope-quit-hook)
  623.     ))
  624.  
  625. (defun cscope-admin-quit-and-kill-buffer (&rest symbol)
  626.   "Tell the cscope subprocess to terminate.
  627. You can achieve the same effect by simply killing the affiliated cscope
  628. output buffer or by exiting emacs.  Any arguments to this function are
  629. ignored."
  630.   (interactive)
  631.   (cscope-admin-quit)
  632.   (let* (
  633.          (cscope-list (cscope:pick-description-list cscope-id))
  634.          (cscope-label (cscope:label-of-list cscope-list))
  635.          (cscope-buffer-name (cscope:bname-from-label cscope-label))
  636.          )
  637.     (if (get-buffer cscope-buffer-name)
  638.         (kill-buffer cscope-buffer-name)))
  639. )
  640.  
  641. (defun cscope-goback-and-goforth ()
  642.   "Return to the affiliated cscope buffer and advance the cursor by one line.
  643. The affect of this will usually be to help in stepping through references
  644. in the cscope output buffer.  See also \"cscope-interpret-output-line\".
  645. After the cursor has been positioned, the optional user-supplied
  646. \"cscope-b-and-f-hook\" is run.  A prefix argument causes
  647. the current window to be used for the cscope output buffer."
  648.   (interactive)
  649.   (if (and cscope:affiliated-buffer (get-buffer cscope:affiliated-buffer))
  650.       (if (and current-prefix-arg
  651.                (not (get-buffer-window cscope:affiliated-buffer)))
  652.           (switch-to-buffer cscope:affiliated-buffer)
  653.         (pop-to-buffer cscope:affiliated-buffer))
  654.     (error "CSCOPE: No affiliated cscope output buffer"))
  655.   (forward-line)
  656.   (run-hooks 'cscope-b-and-f-hook))
  657.  
  658. (defun cscope-interpret-output-line ()
  659.   "Parse the line under the cursor as a cscope output reference line.
  660. Try to visit the named file and place the cursor on the mentioned line number.
  661. After the cursor has been positioned, run the optional user-supplied
  662. \"cscope-interpret-output-hook\".  A prefix argument causes
  663. the current window to be used for the visited file."
  664.   (interactive)
  665.   (beginning-of-line)
  666.   (if (not (looking-at cscope-output-line-regexp))
  667.       (error "CSCOPE: Line not understood as a cscope reference line")
  668.     (let (
  669.           (cscope:filename (buffer-substring
  670.                      (match-beginning cscope-output-file-place)
  671.                      (match-end cscope-output-file-place)))
  672.           (linenumb (buffer-substring
  673.                      (match-beginning cscope-output-line-place)
  674.                      (match-end cscope-output-line-place)))
  675.           (function (buffer-substring
  676.                      (match-beginning cscope-output-func-place)
  677.                      (match-end cscope-output-func-place)))
  678.           (find-file-not-found-hooks (list 'cscope:file-not-found))
  679.           (affiliated-buffer (buffer-name))
  680.           (cscope-id-affiliated cscope-id)
  681.           )
  682.       (and (fboundp 'cscope-filename-fixxer-raw)
  683.            (setq cscope:filename (funcall cscope-filename-fixxer-raw cscope:filename)))
  684.       (if (not (file-name-absolute-p cscope:filename))
  685.           (setq cscope:filename (cscope:fulfill-relative-path cscope:filename)))
  686.       (and (fboundp 'cscope-filename-fixxer-cooked)
  687.            (setq cscope:filename (funcall cscope-filename-fixxer-cooked cscope:filename)))
  688.       (if current-prefix-arg
  689.           (find-file cscope:filename)
  690.         (find-file-other-window cscope:filename))
  691.       (setq cscope:affiliated-buffer affiliated-buffer)
  692.       (if (not cscope-id) (setq cscope-id cscope-id-affiliated))
  693.       (goto-line (string-to-int linenumb))
  694.       (message "CSCOPE: Function: %s" function)
  695.       (run-hooks 'cscope-interpret-output-hook)
  696.       ))
  697.   )
  698.  
  699. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  700. ; only implementation stuff below here
  701. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  702.  
  703. ; A buffer-local internal variable that is used to navigate back to the
  704. ; most recent previous cscope buffer.  Used by cscope-goback-and-goforth.
  705. (defvar cscope:affiliated-buffer nil)
  706. (make-variable-buffer-local 'cscope:affiliated-buffer)
  707.  
  708. ; Gets a piece of menu text and strips off the last two characters, "%s"
  709. (defun cscope:get-menu-subtext (menu-item-key)
  710.   (substring (cdr (assoc menu-item-key cscope:menu-text-list)) 0 -2))
  711.  
  712. ; Used to pick up buffer contents near point that match regexp.
  713. ; Works by backing up until no longer looking at something matching
  714. ; the regular expression, then finding the exact bounds by searching
  715. ; forward.
  716. (defun cscope:looking-at (regexp)
  717.   (let ((fore-marker nil))
  718.     (save-excursion
  719.       (if (or (looking-at regexp) (re-search-backward regexp nil t))
  720.           (progn
  721.             (while (and (looking-at regexp) (not (bobp))) (backward-char 1))
  722.             (if (re-search-forward regexp nil t)
  723.                 (buffer-substring (match-beginning 0) (point-marker))
  724.               (identity "")))
  725.         (identity "")))))
  726.  
  727. (defun cscope:gather-c-symbol (menu-item-key)
  728.   (list (read-string (cscope:get-menu-subtext menu-item-key)
  729.                      (cscope:looking-at cscope-c-symbol-regexp))))
  730.  
  731. (defun cscope:gather-file-name (menu-item-key)
  732.   (list (read-string (cscope:get-menu-subtext menu-item-key)
  733.                      (cscope:looking-at cscope-filename-regexp))))
  734.  
  735. ; no default used for text string, grep/egrep patterns
  736. (defun cscope:gather-text-string (menu-item-key)
  737.   (list (read-string (cscope:get-menu-subtext menu-item-key))))
  738.   
  739. ; Low-level function for passing queries to the "cscope" subprocess.
  740. ; "menu-item-key" and "item-argument" are what "cscope" is
  741. ; expecting (see the "cscope" man page).
  742. (defun cscope:query-omnibus (menu-item-key &optional item-argument)
  743.   (let* (symbol do-this cscope-process)
  744.     (setq symbol (if item-argument item-argument ""))
  745.     (setq do-this  ;; string to identify (in the cscope buffer) what's asked
  746.           (format
  747.            (concat (cdr (assoc menu-item-key cscope:menu-text-list)) "\n")
  748.            symbol))
  749.     (setq cscope-process
  750.           (cscope:pname-from-label
  751.            (cscope:label-of-list
  752.             (cscope:pick-description-list cscope-id))))
  753.     (if (or (eq (process-status cscope-process) 'run)
  754.             (not (string-equal menu-item-key "q")))
  755.         (progn
  756.           (setq cscope-process (cscope:guarantee-process do-this))
  757.           (process-send-string
  758.            cscope-process (concat menu-item-key symbol "\n"))
  759.           (accept-process-output cscope-process)
  760.           (goto-char (point-min))
  761.           (forward-line 1)
  762.           (accept-process-output)
  763.           (if (looking-at "cscope: ") (forward-line 1))
  764.           (run-hooks 'cscope-query-hook)
  765.           ))))
  766.  
  767. ; Obviously, these are intended to match the text of menu items in
  768. ; in the fullscreen version of cscope.  I've also added the "admin"
  769. ; items available under line-oriented mode.  "P" is used automatically
  770. ; (and invisibly) by the interface.
  771. (defconst cscope:menu-text-list
  772.     '(("0" . "Find this C symbol: %s")
  773.       ("1" . "Find this global definition: %s")
  774.       ("2" . "Find functions called by this function: %s")
  775.       ("3" . "Find functions calling this function: %s")
  776.       ("4" . "Find this text string: %s")
  777.       ("5" . "Find this grep pattern: %s")
  778.       ("6" . "Find this egrep pattern: %s")
  779.       ("7" . "Find this file: %s")
  780.       ("8" . "Find files #including this file: %s")
  781.       ("9" . "Find all functions and C++ classes")
  782.       ("c" . "Toggle ignore/use letter case when searching")
  783.       ("r" . "Rebuild the symbol database")
  784.       ("P" . "Print relative-path prefix")
  785.       ("q" . "Quit cscope"))
  786. )
  787.  
  788. ; mapping back and forth between label and buffer/process names
  789. (defconst cscope:bname-prefix "cscope: ")
  790. (defconst cscope:bname-prefix-length (length cscope:bname-prefix))
  791. (defconst cscope:bname-suffix " Output")
  792. (defconst cscope:bname-suffix-length (length cscope:bname-suffix))
  793. (defun cscope:bname-from-label (label)
  794.   (concat cscope:bname-prefix label cscope:bname-suffix))
  795. (defun cscope:label-from-bname (name)
  796.   (substring
  797.    (substring name 0 (- cscope:bname-suffix-length))
  798.    cscope:bname-prefix-length))
  799.  
  800. (defconst cscope:pname-prefix "cscope: ")
  801. (defconst cscope:pname-prefix-length (length cscope:pname-prefix))
  802. (defconst cscope:pname-suffix " Process")
  803. (defconst cscope:pname-suffix-length (length cscope:pname-suffix))
  804. (defun cscope:pname-from-label (label)
  805.   (concat cscope:pname-prefix label cscope:pname-suffix))
  806. (defun cscope:label-from-pname (name)
  807.   (substring
  808.    (substring name 0 (- cscope:pname-suffix-length))
  809.    cscope:pname-prefix-length))
  810.  
  811. ; if the appropriate cscope subprocess is not already running, start it
  812. ; up, initialize buffers, etc;  if it is running, just do the buffer biz
  813. (defun cscope:guarantee-process (do-this)
  814.   (let* (
  815.          (cscope-list (cscope:pick-description-list cscope-id))
  816.          (cscope-label (cscope:label-of-list cscope-list))
  817.          (cscope-buffer-name (cscope:bname-from-label cscope-label))
  818.          (cscope-process-name (cscope:pname-from-label cscope-label))
  819.          (cscope-process nil)
  820.          (cd-place (if (cscope:cdplace-of-list cscope-list) (cscope:cdplace-of-list cscope-list) default-directory))
  821.          )
  822.     (if (eq (process-status cscope-process-name) 'run)
  823.         (save-excursion (set-buffer cscope-buffer-name) (erase-buffer))
  824.       (message "CSCOPE: Starting process for %s ..." cscope-label)
  825.       (and (get-buffer cscope-buffer-name) (kill-buffer cscope-buffer-name))
  826.       (setq cscope-process
  827.             (let (
  828.                   (process-connection-type nil) ; use a pipe
  829.                   (default-directory cd-place))
  830.               (apply 'start-process cscope-process-name cscope-buffer-name (cscope:command-of-list cscope-list))))
  831.       (process-kill-without-query cscope-process)
  832.       (cscope:figure-out-path-prefix cscope-label cscope-buffer-name cscope-process)
  833.       (message "CSCOPE: Starting process for %s ... started" cscope-label)
  834.       (run-hooks 'cscope-start-process-hook)
  835.       )
  836.     (if (and current-prefix-arg
  837.              (not (get-buffer-window cscope-buffer-name)))
  838.         (switch-to-buffer cscope-buffer-name)
  839.       (pop-to-buffer cscope-buffer-name))
  840.     (setq cscope-process (get-process cscope-process-name))
  841.     (if (not cscope-id) (setq cscope-id cscope-label))
  842.     (use-local-map cscope-keymap)
  843.     (insert do-this)
  844.     (set-marker (process-mark cscope-process) (point-max))
  845.     (identity cscope-process)
  846. ))
  847.  
  848. ; keep a list of path prefixes that can be discovered by asking cscope
  849. (defvar cscope:path-prefix-table nil)
  850.  
  851. (defun cscope:figure-out-path-prefix (cscope-label cscope-buffer-name cscope-process)
  852.   (set-buffer cscope-buffer-name)
  853.   (goto-char (point-min))
  854.   (while (and
  855.           (eq (process-status cscope-process) 'run)
  856.           (not (re-search-forward "^>>" nil t)))
  857.     (goto-char (point-min))
  858.     (accept-process-output))
  859.   (if (not (eq (process-status cscope-process) 'run))
  860.       (message "CSCOPE: Dead process for %s" cscope-label)
  861.     (erase-buffer)
  862.     (process-send-string cscope-process "P\n")
  863.     (while (and
  864.             (eq (process-status cscope-process) 'run)
  865.             (not (re-search-forward "^>>" nil t)))
  866.       (goto-char (point-min))
  867.       (accept-process-output))
  868.     (goto-char (point-min))
  869.     (if (not (looking-at ".*cscope.* unknown ")) ;; sometimes no P support
  870.         (progn
  871.           (end-of-line)
  872.           (let* (
  873.                  (path-prefix (buffer-substring (point-min) (point)))
  874.                  (list-item
  875.                   (if cscope:path-prefix-table
  876.                       (assoc cscope-label cscope:path-prefix-table) nil))
  877.                  )
  878.             (if list-item
  879.                 (setcdr list-item path-prefix)
  880.               (setq cscope:path-prefix-table
  881.                     (cons '(cscope-label . path-prefix)
  882.                           cscope:path-prefix-table)))
  883.                  )))
  884.     )
  885.   (erase-buffer)
  886.   )
  887.  
  888. (defun cscope:pick-description-list (cscope-id)
  889.   (if (and cscope-master-info-table (assoc cscope-id cscope-master-info-table))
  890.       (assoc cscope-id cscope-master-info-table)
  891.     (identity cscope-master-info-default)))
  892.  
  893. ; catch the file-not-found situation so that a new empty file isn't just
  894. ; opened up as a routine matter; instead, give a message
  895. (defun cscope:file-not-found ()
  896.   (if cscope-file-not-found-hook
  897.       (run-hooks 'cscope-file-not-found-hook)
  898.     (kill-buffer (get-file-buffer cscope:filename))
  899.     (error "CSCOPE: Can't find file %s" cscope:filename)))
  900.  
  901. ; convert cscope's relative pathnames into absolute pathnames;
  902. ; try computed path prefix, user-specified path prefix, and user-specified
  903. ; "cd place"
  904. (defun cscope:fulfill-relative-path (filename)
  905.   (let* (
  906.         (list-item
  907.          (if cscope:path-prefix-table
  908.              (assoc cscope-id cscope:path-prefix-table) nil))
  909.         (prefix (if list-item (cdr list-item) nil))
  910.         (cscope-list (cscope:pick-description-list cscope-id))
  911.         )
  912.     (if (not prefix) (setq prefix (cscope:pathprefix-of-list cscope-list)))
  913.     (if (not prefix) (setq prefix (cscope:cdplace-of-list cscope-list)))
  914.     (if prefix
  915.         (format "%s/%s" prefix filename)
  916.       (identity filename))
  917.     )
  918. )
  919.  
  920. (provide 'cscope)
  921.  
  922.  
  923.  
  924.