changeset 25899:e5e3310746eb

New file. Use Gnat for lookup and completion in Ada mode
author Gerd Moellmann <gerd@gnu.org>
date Thu, 07 Oct 1999 14:25:59 +0000
parents a39db912a76f
children f14be0689a02
files lisp/progmodes/ada-xref.el
diffstat 1 files changed, 1766 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/progmodes/ada-xref.el	Thu Oct 07 14:25:59 1999 +0000
@@ -0,0 +1,1766 @@
+;; @(#) ada-xref.el --- use Gnat for lookup and completion in Ada mode
+
+;; Copyright (C) 1994-1999 Free Software Foundation, Inc.
+
+;; Author: Markus Heritsch <Markus.Heritsch@studbox.uni-stuttgart.de>
+;;      Rolf Ebert <ebert@inf.enst.fr>
+;;      Emmanuel Briot <briot@gnat.com>
+;; Maintainer: Emmanuel Briot <briot@gnat.com>
+;; Ada Core Technologies's version:   $Revision: 1.75 $
+;; Keywords: languages ada xref
+
+;; This file is not part of GNU Emacs.
+
+;; 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 GNU Emacs; see the file COPYING.  If not, write to
+;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+;;; Commentary:
+;;; This Package provides a set of functions to use the output of the
+;;; cross reference capabilities of the GNAT Ada compiler
+;;; for lookup and completion in Ada mode.
+;;;
+;;; The functions provided are the following ones :
+;;;    - `ada-complete-identifier': completes the current identifier as much as
+;;;      possible, depending of the known identifier in the unit
+;;;    - `ada-point-and-xref': moves the mouse pointer and shows the declaration
+;;;      of the selected identifier (either in the same buffer or in another
+;;;      buffer
+;;;    - `ada-goto-declaration': shows the declaration of the selected
+;;;      identifier (the one under the cursor), either in the same buffer or in
+;;;      another buffer
+;;;    - `ada-goto-declaration-other-frame': same as previous, but opens a new
+;;      frame to show the declaration
+;;;    - `ada-compile-application': recompile your whole application, provided
+;;;      that a project file exists in your directory
+;;;    - `ada-run-application': run your application directly from emacs
+;;;    - `ada-reread-prj-file': force emacs to read your project file again.
+;;;      Otherwise, this file is only read the first time emacs needs some
+;;;      informations, which are then kept in memory
+;;;    - `ada-change-prj': change the prj file associated with a buffer
+;;;    - `ada-change-default-prj': change the default project file used for
+;;;      every new buffer
+;;;
+;;; If a file *.`adp' exists in the ada-file directory, then it is
+;;; read for configuration informations. It is read only the first
+;;; time a cross-reference is asked for, and is not read later.
+
+;;; You need Emacs >= 20.2 to run this package
+
+;; ----- Requirements -----------------------------------------------------
+
+(require 'compile)
+(require 'comint)
+
+;; ----- Dynamic byte compilation -----------------------------------------
+(defvar byte-compile-dynamic nil)
+(make-local-variable 'byte-compile-dynamic)
+(setq byte-compile-dynamic t)
+
+;; ------ Use variables
+(defcustom ada-xref-other-buffer t
+  "*if non-nil then either use a buffer in the same frame or another frame.
+If Nil, always jump to the declaration in the same buffer"
+  :type 'boolean :group 'ada)
+
+(defcustom ada-xref-create-ali t
+  "*if non-nil, run gcc whenever it is needed
+if nil, the cross-reference mode will never run gcc"
+  :type 'boolean :group 'ada)
+
+(defcustom ada-xref-confirm-compile nil
+  "*if non-nil, ask for command confirmation before compiling or
+running the application"
+  :type 'boolean :group 'ada)
+
+(defcustom ada-krunch-args "0"
+  "*Maximum number of characters for filename create by gnatkr
+Set to 0, if you don't use crunched filenames."
+  :type 'string :group 'ada)
+
+(defcustom ada-prj-default-comp-cmd "${cross_prefix}gcc -c -g -gnatq ${comp_opt} -I${src_dir}"
+  "*Default command to be used to compile a single file.
+Emacs will add the filename at the end of this command.
+This is the same syntax as in the project file."
+  :type 'string :group 'ada)
+
+(defcustom ada-prj-default-make-cmd
+  (concat "${cross_prefix}gnatmake ${main} -aI${src_dir} -aO${obj_dir} "
+          "-g -gnatq -cargs ${comp_opt} "
+          "-bargs ${bind_opt} -largs ${link_opt}")
+  "*Default command to be used to compile the application.
+This is the same syntax as in the project file."
+  :type 'string :group 'ada)
+
+(defcustom ada-prj-default-project-file ""
+  "*Non nil means always use this project file, no matter what the
+directory is. Emacs will not try to use the standard algorithm to
+find the project file.
+Note: you can use M-<TAB> in the customization buffer for completion"
+  :type '(file :must-match t) :group 'ada)
+
+(defcustom ada-gnatstub-opts "-q -I${src_dir}"
+  "*List of the options to pass to gnatsub when generating the body from
+a spec file. This has the same syntax as in the project file (with
+variable substitution"
+  :type 'string :group 'ada)
+
+(defcustom ada-always-ask-project nil
+  "*Non-nil means ask for the name of a project file to use when none is
+found by the standard algorithm.
+Nil means use default values when no project file was found")
+
+;; ------- Nothing to be modified by the user below this
+(defvar ada-last-prj-file ""
+  "Name of the last project file entered by the user, when the
+default algorithm did not find any possible project file")
+
+(defvar ada-check-switch " -gnats "
+  "Switch added to the command line to check the current file")
+
+(defvar ada-project-file-extension ".adp"
+  "The extension used for project files")
+
+(defconst is-windows (memq system-type (quote (windows-nt)))
+  "true if we are running on windows NT or windows 95")
+
+(defvar ada-xref-pos-ring '()
+  "This is the list of all the positions we went to with the
+cross-references features. This is used to go back to these positions.")
+
+(defconst ada-xref-pos-ring-max 16
+  "Number of positions kept in the list ada-xref-pos-ring")
+
+(defvar ada-operator-re
+  "\\+\\|-\\|/\\|\\*\\|=\\|mod\\|and\\|not\\|or\\|xor\\|<=\\|<\\|>=\\|>"
+  "Regexp to match for operators")
+
+(defvar ada-xref-default-prj-file nil
+  "name of the default prj file, per directory.
+Every directory is potentially associated with a default project file
+If it is nil, then the first prj file loaded will be the default for this
+emacs session")
+
+;; These variables will be overwritted by buffer-local variables
+(defvar ada-prj-prj-file nil
+  "Name of the project file for the current ada buffer")
+(defvar ada-prj-src-dir nil
+  "List of directories to look into for ada sources")
+(defvar ada-prj-obj-dir nil
+  "List of directories to look into for object and .ali files")
+(defvar ada-prj-comp-opt nil
+  "Switches to use on the command line for the default compile
+command (gcc)")
+(defvar ada-prj-bind-opt nil
+  "Switches to use on the command line for the default bind
+command (gnatbind)")
+(defvar ada-prj-link-opt nil
+  "Switches to use on the command line for the default link
+command (gnatlink)")
+(defvar ada-prj-comp-cmd nil
+  "Command to use to compile the current file only")
+(defvar ada-prj-make-cmd nil
+  "Command to use to compile the whole current application")
+(defvar ada-prj-run-cmd nil
+  "Command to use to run the current application")
+(defvar ada-prj-debug-cmd nil
+  "Command to use to run the debugger")
+(defvar ada-prj-main nil
+  "Name of the main programm of the current application")
+(defvar ada-prj-remote-machine nil
+  "Name of the machine to log on before a compilation")
+(defvar ada-prj-cross-prefix nil
+  "Prefix to be added to the gnatmake, gcc, ... commands when
+using a cross-compilation environment.
+A '-' is automatically added at the end if not already present.
+For instance, the compiler is called `ada-prj-cross-prefix'gnatmake")
+
+;; ----- Keybindings ------------------------------------------------------
+
+(defun ada-add-keymap ()
+  "Add new key bindings when using ada-xrel.el"
+  (interactive)
+  (if ada-xemacs
+      (progn
+        (define-key ada-mode-map '(shift button3) 'ada-point-and-xref)
+        (define-key ada-mode-map '(control tab) 'ada-complete-identifier))
+    (define-key ada-mode-map [C-tab] 'ada-complete-identifier)
+    (define-key ada-mode-map [S-mouse-3] 'ada-point-and-xref))
+
+  (define-key ada-mode-map "\C-co"    'ff-find-other-file)
+  (define-key ada-mode-map "\C-c5\C-d" 'ada-goto-declaration-other-frame)
+  (define-key ada-mode-map "\C-c\C-d" 'ada-goto-declaration)
+  (define-key ada-mode-map "\C-c\C-s" 'ada-xref-goto-previous-reference)
+  (define-key ada-mode-map "\C-c\C-x" 'ada-reread-prj-file)
+  (define-key ada-mode-map [f10] 'next-error)
+  (define-key ada-mode-map "\C-c\C-c" 'ada-compile-application)
+  (define-key ada-mode-map "\C-cb"  'ada-buffer-list)
+  (define-key ada-mode-map "\C-cc"  'ada-change-prj)
+  (define-key ada-mode-map "\C-cd"  'ada-change-default-prj)
+  (define-key ada-mode-map "\C-cg"  'ada-gdb-application)
+  (define-key ada-mode-map "\C-cr"  'ada-run-application)
+  (define-key ada-mode-map "\C-c\C-o" 'ada-goto-parent)
+  (define-key ada-mode-map "\C-c\C-r" 'ada-find-references)
+  (define-key ada-mode-map "\C-c\C-v" 'ada-check-current)
+  )
+
+;; ----- Menus --------------------------------------------------------------
+(defun ada-add-ada-menu ()
+  "Add some items to the standard Ada mode menu (the menu defined in
+ada-mode.el)"
+  (interactive)
+
+  (if ada-xemacs
+      (progn
+        (add-menu-button '("Ada") ["Check file" ada-check-current t] "Goto")
+        (add-menu-button '("Ada") ["Compile file" ada-compile-current t] "Goto")
+        (add-menu-button '("Ada") ["Build" ada-compile-application t] "Goto")
+        (add-menu-button '("Ada") ["Run" ada-run-application t] "Goto")
+        (add-menu-button '("Ada") ["Debug" ada-gdb-application t] "Goto")
+        (add-menu-button '("Ada") ["--" nil t] "Goto")
+        (add-submenu '("Ada") '("Project"
+                                ["Associate"   ada-change-prj t]
+                                ["Set Default" ada-set-default-project-file t]
+                                ["List" ada-buffer-list t])
+                     "Goto")
+        (add-menu-button '("Ada" "Goto") ["Goto Parent Unit" ada-goto-parent t]
+                         "Next compilation error")
+        (add-menu-button '("Ada" "Goto") ["Goto References to any entity" ada-find-any-references t]
+                         "Next compilation error")
+        (add-menu-button '("Ada" "Goto") ["List References" ada-find-references t]
+                         "Next compilation error")
+        (add-menu-button '("Ada" "Goto") ["Goto Declaration Other Frame"
+                                          ada-goto-declaration-other-frame t]
+                         "Next compilation error")
+        (add-menu-button '("Ada" "Goto") ["Goto Declaration/Body" ada-goto-declaration t]
+                         "Next compilation error")
+        (add-menu-button '("Ada" "Goto") ["Goto Previous Reference" ada-xref-goto-previous-reference t]
+                         "Next compilation error")
+        (add-menu-button '("Ada" "Goto") ["--" nil t]
+                         "Next compilation error")
+        (add-menu-button '("Ada" "Edit") ["Complete Identifier" ada-complete-identifier t]
+                         "Indent Line")
+        (add-menu-button '("Ada" "Edit") ["--------" nil t]
+                         "Indent Line")
+	(add-menu-button '("Ada" "Help") ["Gnat User Guide" (info "gnat_ug")])
+	(add-menu-button '("Ada" "Help") ["Gnat Reference Manual"
+					  (info "gnat_rm")])
+	(add-menu-button '("Ada" "Help") ["Gcc Documentation" (info "gcc")])
+	(add-menu-button '("Ada" "Help") ["Gdb Documentation" (info "gdb")])
+        )
+
+    ;; for Emacs
+    (define-key-after (lookup-key ada-mode-map [menu-bar Ada]) [Check]
+      '("Check file" . ada-check-current) 'Customize)
+    (define-key-after (lookup-key ada-mode-map [menu-bar Ada]) [Compile]
+      '("Compile file" . ada-compile-current) 'Check)
+    (define-key-after (lookup-key ada-mode-map [menu-bar Ada]) [Build]
+      '("Build" . ada-compile-application) 'Compile)
+    (define-key-after (lookup-key ada-mode-map [menu-bar Ada]) [Run]
+      '("Run" . ada-run-application) 'Build)
+    (define-key-after (lookup-key ada-mode-map [menu-bar Ada]) [Debug]
+      '("Debug" . ada-gdb-application) 'Run)
+    (define-key-after (lookup-key ada-mode-map [menu-bar Ada]) [rem]
+      '("--" . nil) 'Debug)
+    (define-key-after (lookup-key ada-mode-map [menu-bar Ada]) [Project]
+      (cons "Project" (easy-menu-create-menu
+                       "Project"
+                       '(["Associate" ada-change-prj t]
+                         ["Set Default" ada-set-default-project-file t]
+                         ["List" ada-buffer-list t])))
+      'rem)
+
+    (let ((help-submenu (lookup-key ada-mode-map [menu-bar Ada Help]))
+          (goto-submenu (lookup-key ada-mode-map [menu-bar Ada Goto]))
+          (edit-submenu (lookup-key ada-mode-map [menu-bar Ada Edit])))
+
+      (define-key help-submenu [Gnat_ug]
+        '("Gnat User Guide" . (lambda() (interactive) (info "gnat_ug"))))
+      (define-key help-submenu [Gnat_rm]
+        '("Gnat Reference Manual" . (lambda() (interactive) (info "gnat_rm"))))
+      (define-key help-submenu [Gcc]
+        '("Gcc Documentation" . (lambda() (interactive) (info "gcc"))))
+      (define-key help-submenu [gdb]
+        '("Ada Aware Gdb Documentation" . (lambda() (interactive) (info "gdb"))))
+      (define-key goto-submenu [rem]    '("----" . nil))
+      (define-key goto-submenu [Parent] '("Goto Parent Unit" . ada-goto-parent))
+      (define-key goto-submenu [References-any]
+        '("Goto References to any entity" . ada-find-any-references))
+      (define-key goto-submenu [References]
+        '("List References" . ada-find-references))
+      (define-key goto-submenu [Prev]
+        '("Goto Previous Reference" . ada-xref-goto-previous-reference))
+      (define-key goto-submenu [Decl-other]
+        '("Goto Declaration Other Frame" . ada-goto-declaration-other-frame))
+      (define-key goto-submenu [Decl]
+        '("Goto Declaration/Body" . ada-goto-declaration))
+
+      (define-key edit-submenu [rem] '("----" . nil))
+      (define-key edit-submenu [Complete] '("Complete Identifier"
+                                            . ada-complete-identifier))
+      )
+    ))
+
+;; ----- Utilities -------------------------------------------------
+
+(defun ada-require-project-file ()
+  "If no project file is assigned to this buffer, load one"
+  (if (not ( my-local-variable-if-set-p 'ada-prj-src-dir (current-buffer)))
+      (ada-parse-prj-file (ada-prj-find-prj-file))))
+
+(defun my-local-variable-if-set-p (variable &optional buffer)
+  (and (local-variable-p variable buffer)
+       (save-excursion
+         (set-buffer buffer)
+         (symbol-value variable))))
+
+(defun ada-xref-push-pos (filename position)
+  "Push (FILENAME, POSITION) on the position ring for cross-references"
+  (setq ada-xref-pos-ring (cons (list position filename) ada-xref-pos-ring))
+  (if (> (length ada-xref-pos-ring) ada-xref-pos-ring-max)
+      (setcdr (nthcdr (1- ada-xref-pos-ring-max) ada-xref-pos-ring) nil)))
+
+(defun ada-xref-goto-previous-reference ()
+  "Go to the previous cross-reference we were on"
+  (interactive)
+  (if ada-xref-pos-ring
+      (progn
+        (let ((pos (car ada-xref-pos-ring)))
+          (setq ada-xref-pos-ring (cdr ada-xref-pos-ring))
+          (find-file (car (cdr pos)))
+          (goto-char (car pos))))))
+
+(defun ada-convert-file-name (name)
+  "Function to convert from the buffer file name to the name given in
+argument to the ada-compile-current function.  This function is
+overridden on VMS to convert from VMS filename to Unix filenames"
+  name)
+
+(defun ada-set-default-project-file (name)
+  (interactive "fName of project file:")
+  (set 'ada-prj-default-project-file name)
+  (ada-reread-prj-file t)
+  )
+
+;; ------ Handling the project file -----------------------------
+
+(defun ada-replace-substring (cmd-string search-for replace-with)
+  "Replace all instances of SEARCH-FOR with REPLACE-WITH in
+string CMD-STRING"
+  (while (string-match search-for cmd-string)
+    (setq cmd-string (replace-match replace-with t t cmd-string)))
+  cmd-string)
+
+(defun ada-treat-cmd-string (cmd-string)
+  "Replace meta-sequences like ${...} with the appropriate value in CMD-STRING.
+The current buffer must be the one where all local variable are definied (that
+is the ada source)"
+
+  (if ( my-local-variable-if-set-p 'ada-prj-src-dir (current-buffer))
+      (if  (string-match "\\(-[^-\$I]*I\\)\${src_dir}" cmd-string)
+          (progn
+            (let ((str-def (substring cmd-string (match-beginning 1)
+                                      (match-end 1))))
+              (setq cmd-string
+                    (ada-replace-substring cmd-string
+                                           "\\(-[^-\$I]*I\\)\${src_dir}"
+                      (mapconcat
+                      (lambda (x) (concat str-def x))
+                      ada-prj-src-dir " ")))))))
+  (if ( my-local-variable-if-set-p 'ada-prj-obj-dir (current-buffer))
+      (if (string-match "\\(-[^-\$O]*O\\)\${obj_dir}" cmd-string)
+          (progn
+            (let ((str-def (substring cmd-string (match-beginning 1)
+                                      (match-end 1))))
+              (setq cmd-string
+                    (ada-replace-substring cmd-string
+                                           "\\(-[^-\$O]*O\\)\${obj_dir}"
+                        (mapconcat
+                         (lambda (x) (concat str-def x))
+                         ada-prj-obj-dir
+                         " ")))))))
+  (if ( my-local-variable-if-set-p 'ada-prj-remote-machine (current-buffer))
+      (setq cmd-string
+            (ada-replace-substring cmd-string "\${remote_machine}"
+                                   ada-prj-remote-machine)))
+  (if ( my-local-variable-if-set-p 'ada-prj-comp-opt (current-buffer))
+      (setq cmd-string
+            (ada-replace-substring cmd-string "\${comp_opt}"
+                                   ada-prj-comp-opt)))
+  (if ( my-local-variable-if-set-p 'ada-prj-bind-opt (current-buffer))
+      (setq cmd-string
+            (ada-replace-substring cmd-string "\${bind_opt}"
+                                   ada-prj-bind-opt)))
+  (if ( my-local-variable-if-set-p 'ada-prj-link-opt (current-buffer))
+      (setq cmd-string
+            (ada-replace-substring cmd-string "\${link_opt}"
+                                   ada-prj-link-opt)))
+  (if ( my-local-variable-if-set-p 'ada-prj-main (current-buffer))
+      (setq cmd-string
+            (ada-replace-substring cmd-string "\${main}"
+                                   ada-prj-main)))
+  (if ( my-local-variable-if-set-p 'ada-prj-cross-prefix (current-buffer))
+      (setq cmd-string
+            (ada-replace-substring cmd-string "\${cross_prefix}"
+                                   ada-prj-cross-prefix)))
+  cmd-string)
+
+
+(defun ada-prj-find-prj-file (&optional no-user-question)
+  "Find the prj file associated with the current buffer
+The rules are the following ones :
+- If the buffer is already associated with a prj file, use this one
+- else if there's a default prj file for the same directory use it
+- else if a prj file with the same filename exists, use it
+- else if there's only one prj file in the directory, use it
+- else if there are more than one prj file, ask the user
+- else if there is no prj file and no-user-question is nil, ask the user
+  for the project file to use."
+  (let* ((current-file (buffer-file-name))
+         (first-choice (concat
+                        (file-name-sans-extension current-file)
+                        ada-project-file-extension))
+         (dir          (file-name-directory current-file))
+
+	 ;; on Emacs 20.2, directory-files does not work if
+	 ;; parse-sexp-lookup-properties is set
+	 (parse-sexp-lookup-properties nil)
+         (prj-files    (directory-files
+                        dir t
+                        (concat ".*" (regexp-quote ada-project-file-extension) "$")))
+         (choice       nil)
+         (default      (assoc dir ada-xref-default-prj-file))
+         )
+
+    (cond
+
+     ((my-local-variable-if-set-p 'ada-prj-prj-file (current-buffer))
+      ada-prj-prj-file)
+
+     (default                       ;; directory default project file
+       (cdr default))
+
+     ;; global default project file
+     ((and ada-prj-default-project-file
+           (not (string= ada-prj-default-project-file "")))
+      ada-prj-default-project-file)
+
+     ((file-exists-p first-choice)
+      first-choice)
+
+     ((= (length prj-files) 1)
+      (car prj-files))
+
+     ((> (length prj-files) 1)
+      ;; more than one possible prj file => ask the user
+      (with-output-to-temp-buffer "*choice list*"
+        (princ "There are more than one possible project file. Which one should\n")
+        (princ "I use ?\n\n")
+        (princ "  no.   file name  \n")
+        (princ "  ---   ------------------------\n")
+        (let ((counter 1))
+          (while (<= counter (length prj-files))
+            (princ (format "  %2d)    %s\n"
+                           counter
+                           (nth (1- counter) prj-files)))
+            (setq counter (1+ counter))
+            ) ; end of while
+          ) ; end of let
+        ) ; end of with-output-to ...
+      (setq choice nil)
+      (while (or
+              (not choice)
+              (not (integerp choice))
+              (< choice 1)
+              (> choice (length prj-files)))
+        (setq choice (string-to-int
+                      (read-from-minibuffer "Enter No. of your choice: "
+                                            ))))
+      (nth (1- choice) prj-files))
+
+     ((= (length prj-files) 0)
+      ;;  no project file found. Ask the user about it (the default value
+      ;;  is the last one the user entered.
+      (if (or no-user-question (not ada-always-ask-project))
+          nil
+        (setq ada-last-prj-file
+              (read-file-name "project file:" nil ada-last-prj-file))
+        (if (string= ada-last-prj-file "") nil ada-last-prj-file))
+     )
+  )))
+
+
+(defun ada-parse-prj-file (prj-file)
+  "Reads and parses the PRJ-FILE file if it was found.
+The current buffer should be the ada-file buffer"
+
+  (let ((tmp-src-dir  nil)
+        (tmp-obj-dir  nil)
+        (tmp-comp-opt nil)
+        (tmp-bind-opt nil)
+        (tmp-link-opt nil)
+        (tmp-main     nil)
+        (tmp-comp-cmd nil)
+        (tmp-make-cmd nil)
+        (tmp-run-cmd  nil)
+        (tmp-debug-cmd nil)
+        (tmp-remote-machine nil)
+        (tmp-cross-prefix nil)
+        (tmp-cd-cmd   (if prj-file
+                          (concat "cd " (file-name-directory prj-file) " && ")
+                        (concat "cd " (file-name-directory (buffer-file-name (current-buffer))) " && ")))
+        (ada-buffer (current-buffer))
+        )
+    ;; tries to find a project file in the current directory
+    (if prj-file
+        (progn
+          (find-file prj-file)
+
+          ;; first look for the src_dir lines
+          (widen)
+          (goto-char (point-min))
+          (while
+              (re-search-forward "^src_dir=\\(.*\\)" nil t)
+            (progn
+              (setq tmp-src-dir (cons
+                                 (file-name-as-directory
+                                  (match-string 1))
+                                 tmp-src-dir
+                                 ))))
+          ;; then for the obj_dir lines
+          (goto-char (point-min))
+          (while (re-search-forward "^obj_dir=\\(.*\\)" nil t)
+            (setq tmp-obj-dir (cons
+                               (file-name-as-directory
+                                (match-string 1))
+                               tmp-obj-dir
+                               )))
+
+          ;; then for the options lines
+          (goto-char (point-min))
+          (if (re-search-forward "^comp_opt=\\(.*\\)" nil t)
+              (setq tmp-comp-opt (match-string 1)))
+          (goto-char (point-min))
+          (if (re-search-forward "^bind_opt=\\(.*\\)" nil t)
+              (setq tmp-bind-opt (match-string 1)))
+          (goto-char (point-min))
+          (if (re-search-forward "^link_opt=\\(.*\\)" nil t)
+              (setq tmp-link-opt (match-string 1)))
+          (goto-char (point-min))
+          (if (re-search-forward "^main=\\(.*\\)" nil t)
+              (setq tmp-main (match-string 1)))
+          (goto-char (point-min))
+          (if (re-search-forward "^comp_cmd=\\(.*\\)" nil t)
+              (setq tmp-comp-cmd (match-string 1)))
+          (goto-char (point-min))
+          (if (re-search-forward "^remote_machine=\\(.*\\)" nil t)
+              (setq tmp-remote-machine (match-string 1)))
+          (goto-char (point-min))
+          (if (re-search-forward "^cross_prefix=\\(.*\\)" nil t)
+              (setq tmp-cross-prefix (match-string 1)))
+          (goto-char (point-min))
+          (if (re-search-forward "^make_cmd=\\(.*\\)" nil t)
+              (setq tmp-make-cmd (match-string 1)))
+          (goto-char (point-min))
+          (if (re-search-forward "^run_cmd=\\(.*\\)" nil t)
+              (setq tmp-run-cmd (match-string 1)))
+          (goto-char (point-min))
+          (if (re-search-forward "^debug_cmd=\\(.*\\)" nil t)
+              (setq tmp-debug-cmd (match-string 1)))
+
+          ;; kills the project file buffer, and go back to the ada buffer
+          (kill-buffer nil)
+          (set-buffer ada-buffer)
+          ))
+
+    ;; creates local variables (with default values if needed)
+    (set (make-local-variable 'ada-prj-prj-file) prj-file)
+
+    (set (make-local-variable 'ada-prj-src-dir)
+         (if tmp-src-dir (reverse tmp-src-dir)  '("./")))
+
+    (set (make-local-variable 'ada-prj-obj-dir)
+         (if tmp-obj-dir (reverse tmp-obj-dir)  '("./")))
+
+    (set (make-local-variable 'ada-prj-comp-opt)
+         (if tmp-comp-opt tmp-comp-opt ""))
+
+    (set (make-local-variable 'ada-prj-bind-opt)
+         (if tmp-bind-opt tmp-bind-opt ""))
+
+    (set (make-local-variable 'ada-prj-link-opt)
+         (if tmp-link-opt tmp-link-opt ""))
+
+    (set (make-local-variable 'ada-prj-cross-prefix)
+         (if tmp-cross-prefix
+             (if (or (string= tmp-cross-prefix "")
+                     (= (aref tmp-cross-prefix (1- (length tmp-cross-prefix))) ?-))
+                 tmp-cross-prefix
+               (concat tmp-cross-prefix "-"))
+              ""))
+
+    (set (make-local-variable 'ada-prj-main)
+         (if tmp-main tmp-main
+           (substring (buffer-file-name) 0 -4)))
+
+    (set (make-local-variable 'ada-prj-remote-machine)
+         (ada-treat-cmd-string
+          (if tmp-remote-machine tmp-remote-machine "")))
+
+    (set (make-local-variable 'ada-prj-comp-cmd)
+         (ada-treat-cmd-string
+          (if tmp-comp-cmd tmp-comp-cmd
+            (concat tmp-cd-cmd ada-prj-default-comp-cmd))))
+
+    (set (make-local-variable 'ada-prj-make-cmd)
+         (ada-treat-cmd-string
+          (if tmp-make-cmd tmp-make-cmd
+            (concat tmp-cd-cmd ada-prj-default-make-cmd))))
+
+    (set (make-local-variable 'ada-prj-run-cmd)
+         (ada-treat-cmd-string
+          (if tmp-run-cmd tmp-run-cmd
+            (if is-windows "${main}.exe" "${main}"))))
+
+    (set (make-local-variable 'ada-prj-debug-cmd)
+         (ada-treat-cmd-string
+          (if tmp-debug-cmd tmp-debug-cmd
+            (if is-windows
+                "${cross_prefix}gdb ${main}.exe"
+              "${cross_prefix}gdb ${main}"))))
+
+    ;; Add each directory in src_dir to the default prj list
+    (if prj-file
+        (mapcar (lambda (x)
+                  (if (not (assoc (expand-file-name x)
+                                  ada-xref-default-prj-file))
+                      (setq ada-xref-default-prj-file
+                            (cons (cons (expand-file-name x)
+                                        prj-file)
+                                  ada-xref-default-prj-file))))
+                ada-prj-src-dir))
+
+    ;; Add the directories to the search path for ff-find-other-file
+    ;; Do not add the '/' or '\' at the end
+    (set (make-local-variable 'ff-search-directories)
+         (append (mapcar 'directory-file-name ada-prj-src-dir)
+                 ada-search-directories))
+
+    ;; Sets up the compilation-search-path so that Emacs is able to
+    ;; go to the source of the errors in a compilation buffer
+    (setq compilation-search-path ada-prj-src-dir)
+
+    ))
+
+
+(defun ada-find-references (&optional pos)
+  "Find every references to the entity under POS
+Calls gnatfind to find every references"
+  (interactive "")
+  (unless pos
+    (set 'pos (point)))
+  (ada-require-project-file)
+
+  (let* ((identlist (ada-read-identifier pos))
+         (alifile (ada-get-ali-file-name (ada-file-of identlist))))
+
+    (set-buffer (get-file-buffer (ada-file-of identlist)))
+
+    ;;  if the file is more recent than the executable
+    (if (or (buffer-modified-p (current-buffer))
+            (file-newer-than-file-p (ada-file-of identlist) alifile))
+        (ada-find-any-references (ada-name-of identlist)
+                                 (ada-file-of identlist)
+                                 nil nil)
+      (ada-find-any-references (ada-name-of identlist)
+                               (ada-file-of identlist)
+                               (ada-line-of identlist)
+                               (ada-column-of identlist))))
+  )
+
+(defun ada-find-any-references (entity &optional file line column)
+  "Search for references to any entity"
+  (interactive "sEntity name: ")
+  (ada-require-project-file)
+
+  (let* ((command (concat "gnatfind -rf " entity
+                          (if file (concat ":" (file-name-nondirectory file)))
+                          (if line (concat ":" line))
+                          (if column (concat ":" column)))))
+
+    ;;  If a project file is defined, use it
+    (if (my-local-variable-if-set-p 'ada-prj-prj-file (current-buffer))
+        (setq command (concat command " -p" ada-prj-prj-file)))
+
+    (compile-internal command
+                      "No more references"
+                      "gnatfind")
+
+    ;;  Hide the "Compilation" menu
+    (save-excursion
+      (set-buffer "*gnatfind*")
+      (local-unset-key [menu-bar compilation-menu]))
+    )
+  )
+
+(defun ada-buffer-list ()
+  "Display a buffer with all the ada-mode buffers and their associated prj file"
+  (interactive)
+  (save-excursion
+    (set-buffer (get-buffer-create "*Buffer List*"))
+    (setq buffer-read-only nil)
+    (erase-buffer)
+    (setq standard-output (current-buffer))
+    (princ "The following line is a list showing the associations between
+directories and project file. It has the format : ((directory_1 . project_file1)
+(directory2 . project_file2)...)\n\n")
+    (princ ada-xref-default-prj-file)
+    (princ "\n
+ Buffer              Mode         Project file
+ ------              ----         ------------
+\n")
+    (let ((bl (buffer-list)))
+      (while bl
+        (let* ((buffer (car bl))
+               (buffer-name (buffer-name buffer))
+               this-buffer-mode-name
+               this-buffer-project-file)
+          (save-excursion
+            (set-buffer buffer)
+            (setq this-buffer-mode-name
+                  (if (eq buffer standard-output)
+                      "Buffer Menu" mode-name))
+            (if (string= this-buffer-mode-name
+                         "Ada")
+                (setq this-buffer-project-file
+                      (if ( my-local-variable-if-set-p 'ada-prj-prj-file
+                                                   (current-buffer))
+                          (expand-file-name ada-prj-prj-file)
+                        ""))))
+          (if (string= this-buffer-mode-name
+                         "Ada")
+              (progn
+                (princ (format "%-19s  "  buffer-name))
+                  (princ (format "%-6s " this-buffer-mode-name))
+                  (princ this-buffer-project-file)
+                  (princ "\n")
+                  ))
+          ) ;; end let*
+        (setq bl (cdr bl))
+        ) ;; end while
+      );; end let
+    ) ;; end save-excursion
+  (display-buffer "*Buffer List*")
+  (other-window 1)
+  )
+
+(defun ada-change-prj (filename)
+  "Change the project file associated with the current buffer"
+  (interactive "fproject file:")
+
+  ;; make sure we are using an Ada file
+  (if (not (string= mode-name "Ada"))
+    (error "You must be in ada-mode to use this function"))
+
+  ;; create the local variable if necessay
+  (if (not ( my-local-variable-if-set-p 'ada-prj-prj-file (current-buffer)))
+      (make-local-variable 'ada-prj-prj-file))
+
+  ;; ask the user for the new file name
+  (setq ada-prj-prj-file filename)
+
+  ;; force emacs to reread the prj file next-time
+  (ada-reread-prj-file)
+  )
+
+(defun ada-change-default-prj (filename)
+  "Change the default project file used for all ada files from the
+current directory"
+  (interactive "ffile name:")
+  (let ((dir (file-name-directory (buffer-file-name)))
+	(prj (expand-file-name filename)))
+
+    ;; If the directory is already associated with a project file
+    (if (assoc dir ada-xref-default-prj-file)
+      
+	(setcdr (assoc dir ada-xref-default-prj-file) prj)
+      ;; Else create a new element in the list
+      (add-to-list 'ada-xref-default-prj-file (list dir prj)))
+
+    ;; Reparse the project file
+    (ada-parse-prj-file ada-prj-default-project-file)))
+
+
+;; ----- Identlist manipulation -------------------------------------------
+;; An identlist is a vector that is used internally to reference an identifier
+;; To facilitate its use, we provide the following macros
+
+(defmacro ada-make-identlist () (make-vector 8 nil))
+(defmacro ada-name-of   (identlist)    (list 'aref identlist 0))
+(defmacro ada-line-of   (identlist)    (list 'aref identlist 1))
+(defmacro ada-column-of (identlist)    (list 'aref identlist 2))
+(defmacro ada-file-of   (identlist)    (list 'aref identlist 3))
+(defmacro ada-ali-index-of    (identlist) (list 'aref identlist 4))
+(defmacro ada-declare-file-of (identlist) (list 'aref identlist 5))
+(defmacro ada-references-of   (identlist) (list 'aref identlist 6))
+(defmacro ada-on-declaration  (identlist) (list 'aref identlist 7))
+
+(defmacro ada-set-name         (identlist name) (list 'aset identlist 0 name))
+(defmacro ada-set-line         (identlist line) (list 'aset identlist 1 line))
+(defmacro ada-set-column       (identlist col)  (list 'aset identlist 2 col))
+(defmacro ada-set-file         (identlist file) (list 'aset identlist 3 file))
+(defmacro ada-set-ali-index   (identlist index) (list 'aset identlist 4 index))
+(defmacro ada-set-declare-file (identlist file) (list 'aset identlist 5 file))
+(defmacro ada-set-references   (identlist ref)  (list 'aset identlist 6 ref))
+(defmacro ada-set-on-declaration (ident value) (list 'aset ident 7 value))
+
+(defsubst ada-get-ali-buffer (file)
+  "Reads the ali file into a new buffer, and returns this buffer's name"
+  (find-file-noselect (ada-get-ali-file-name file)))
+
+
+
+;; ----- Identifier Completion --------------------------------------------
+(defun ada-complete-identifier (pos)
+  "Tries to complete the identifier around POS.
+The feature is only available if the files where compiled not using the -gnatx
+option"
+  (interactive "d")
+  (ada-require-project-file)
+
+  ;; Initialize function-local variablesand jump to the .ali buffer
+  ;; Note that for regexp search is case insensitive too
+  (let* ((curbuf (current-buffer))
+         (identlist (ada-read-identifier pos))
+         (sofar (concat "^[0-9]+[a-zA-Z][0-9]+[ *]\\("
+                        (regexp-quote (ada-name-of identlist))
+                        "[a-zA-Z0-9_]*\\)"))
+         (completed nil)
+         (symalist nil)
+         (insertpos nil))
+
+    ;; we are already in the .ali buffer
+    (goto-char (point-max))
+
+    ;; build an alist of possible completions
+    (while (re-search-backward sofar nil t)
+      (setq symalist (cons (cons (match-string 1) nil) symalist)))
+
+    (setq completed  (try-completion "" symalist))
+
+    ;; kills .ali buffer
+    (kill-buffer nil)
+
+    ;; deletes the incomplete identifier in the buffer
+    (set-buffer curbuf)
+    (looking-at "[a-zA-Z0-9_]+")
+    (replace-match "")
+    ;; inserts the completed symbol
+    (insert completed)
+    ))
+
+;; ----- Cross-referencing ----------------------------------------
+
+(defun ada-point-and-xref ()
+ "Calls `mouse-set-point' and then `ada-goto-declaration'."
+  (interactive)
+  (mouse-set-point last-input-event)
+  (ada-goto-declaration (point)))
+
+(defun ada-goto-declaration (pos)
+  "Displays the declaration of the identifier around POS.
+The declaration is shown in another buffer if `ada-xref-other-buffer' is non-nil"
+  (interactive "d")
+  (ada-require-project-file)
+  (push-mark pos)
+  (ada-xref-push-pos (buffer-file-name) pos)
+  (ada-find-in-ali (ada-read-identifier pos)))
+
+(defun ada-goto-declaration-other-frame (pos)
+  "Displays the declaration of the identifier around point.
+The declation is shown in another frame if `ada-xref-other-buffer' is non-nil"
+  (interactive "d")
+  (ada-require-project-file)
+  (push-mark pos)
+  (ada-xref-push-pos (buffer-file-name) pos)
+  (ada-find-in-ali (ada-read-identifier pos) t))
+
+(defun ada-compile (command)
+  "Start a compilation, on the machine specified in the project file,
+using command COMMAND"
+
+  (if (and (my-local-variable-if-set-p 'ada-prj-remote-machine (current-buffer))
+           (not (string= ada-prj-remote-machine "")))
+      (set 'command
+           (concat "rsh " ada-prj-remote-machine " '"
+                   command "'")))
+  (compile command))
+
+(defun ada-compile-application ()
+  "Compiles the whole application, using the command find in the gnat.prj file"
+  (interactive)
+  (ada-require-project-file)
+
+  ;; prompt for command to execute
+  (ada-compile
+   (if ada-xref-confirm-compile
+       (read-from-minibuffer "enter command to compile: "
+                             ada-prj-make-cmd)
+     ada-prj-make-cmd))
+  )
+
+(defun ada-compile-current ()
+  "Recompile the current file"
+  (interactive)
+  (ada-require-project-file)
+
+  ;; prompt for command to execute
+  (ada-compile
+   (if ada-xref-confirm-compile
+       (read-from-minibuffer "enter command to compile: "
+                             (concat
+                              ada-prj-comp-cmd " " (ada-convert-file-name (buffer-file-name))))
+     (concat ada-prj-comp-cmd " " (ada-convert-file-name (buffer-file-name)))))
+  )
+
+(defun ada-check-current ()
+  "Recompile the current file"
+  (interactive)
+  (ada-require-project-file)
+
+  ;; prompt for command to execute
+  (let ((command (concat ada-prj-comp-cmd ada-check-switch
+                         (ada-convert-file-name (buffer-file-name)))))
+    (compile
+     (if ada-xref-confirm-compile
+         (read-from-minibuffer "enter command to compile: " command)
+       command))))
+
+
+(defun ada-run-application ()
+  "Run the application"
+  (interactive)
+  (ada-require-project-file)
+
+  (if (and (my-local-variable-if-set-p 'ada-prj-cross-prefix (current-buffer))
+           (not (string= ada-prj-cross-prefix "")))
+      (error "This feature is not supported yet for cross-compilation environments"))
+
+  (let ((command ada-prj-run-cmd)
+        (buffer  (current-buffer)))
+    ;; Search the command name if necessary
+    (if (not (my-local-variable-if-set-p 'ada-prj-run-cmd (current-buffer)))
+        (setq command (file-name-sans-extension (buffer-name)))
+      )
+
+    ;; Ask for the arguments to the command
+    (setq command
+          (read-from-minibuffer "Enter command to execute: "
+                                command))
+
+    ;; Run the command
+    (save-excursion
+      (set-buffer (get-buffer-create "*run*"))
+      (goto-char (point-max))
+      (insert "\nRunning " command "\n\n")
+      (make-comint "run"
+                   (comint-arguments command 0 0)
+                   nil
+                   (comint-arguments command 1 nil))
+      )
+    (display-buffer "*run*")
+
+    ;;  change to buffer *run* for interactive programs
+    (other-window 1)
+    (switch-to-buffer "*run*")
+    )
+  )
+
+
+(defun ada-gdb-application ()
+  "Run the application"
+  (interactive)
+
+  (require 'gud)
+  (let ((buffer (current-buffer))
+        gdb-buffer)
+    (ada-require-project-file)
+
+    (if (and (my-local-variable-if-set-p 'ada-prj-cross-prefix buffer)
+             (not (string= ada-prj-cross-prefix "")))
+        (error "This feature is not supported yet for cross-compilation environments"))
+
+    ;; If the command to use was given in the project file
+    (if (my-local-variable-if-set-p 'ada-prj-debug-cmd buffer)
+	(gdb ada-prj-debug-cmd)
+      ;; Else the user will have to enter the command himself
+      (gdb "")
+      )
+
+    (set 'gdb-buffer (current-buffer))
+    
+    ;;  Switch back to the source buffer
+    ;;  and Activate the debug part in the contextual menu
+    (switch-to-buffer buffer)
+
+    (if (functionp 'gud-make-debug-menu)
+	(gud-make-debug-menu))
+
+    ;;  Warning: on Emacs >= 20.3.8, same-window-regexps includes gud-*,
+    ;;  so the following call to display buffer will select the
+    ;;  buffer instead of displaying it in another window
+    ;;  This is why the second argument to display-buffer is 't'
+    (display-buffer gdb-buffer t)
+    ))
+
+
+(defun ada-reread-prj-file (&optional for-all-buffer)
+  "Forces emacs to read the project file again.
+Otherwise, this file is only read once, and never read again
+If `for-all-buffer' is non-nil, or the function was called with \C-u prefix,
+then do this for every opened buffer"
+  (interactive "P")
+  (if for-all-buffer
+
+      ;; do this for every buffer
+      (mapcar (lambda (x)
+                 (save-excursion
+                   (set-buffer x)
+		   ;; if we have the ada-mode and there is a real file
+		   ;; associated with the buffer
+                   (if (and (string= mode-name "Ada")
+			    (buffer-file-name))
+                       (progn
+                         (kill-local-variable 'ada-prj-src-dir)
+                         (kill-local-variable 'ada-prj-obj-dir)
+                         (ada-parse-prj-file (ada-prj-find-prj-file))))
+                   ))
+               (buffer-list))
+
+    ;; else do this just for the current buffer
+    (kill-local-variable 'ada-prj-src-dir)
+    (kill-local-variable 'ada-prj-obj-dir)
+    (ada-parse-prj-file (ada-prj-find-prj-file)))
+  )
+
+;; ------ Private routines
+
+(defun ada-xref-current (file &optional ali-file-name)
+  "Creates a new ali file from the FILE source file,
+assuming the ali file will be called ALI-FILE-NAME.
+Uses the function `compile' to execute the commands
+defined in the project file."
+  ;; kill old buffer
+  (if (and ali-file-name
+           (get-file-buffer ali-file-name))
+      (kill-buffer (get-file-buffer ali-file-name)))
+  ;; prompt for command to execute
+  (setq compile-command (concat ada-prj-comp-cmd
+                                " "
+                                file))
+  (compile
+   (if ada-xref-confirm-compile
+       (read-from-minibuffer "enter command to execute gcc: "
+                             compile-command)
+     compile-command))
+  )
+
+(defun ada-first-non-nil (list)
+  "Returns the first non-nil element of the list"
+  (cond
+   ((not list) nil)
+   ((car list) (car list))
+   (t (ada-first-non-nil (cdr list)))
+   ))
+
+
+(defun ada-find-ali-file-in-dir (file)
+  "Search for FILE in obj_dir
+The current buffer must be the Ada file"
+  (ada-first-non-nil
+   (mapcar (lambda (x)
+             (if (file-exists-p (concat (file-name-directory x)
+                                        file))
+                 (concat (file-name-directory x) file)
+               nil))
+           ada-prj-obj-dir))
+  )
+
+(defun ada-get-ali-file-name (file)
+  "create the ali file name for the ada-file FILE
+The file is searched for in every directory shown in the
+obj_dir lines of the project file"
+
+  ;; This function has to handle the special case of non-standard
+  ;; file names (i.e. not .adb or .ads)
+  ;; The trick is the following:
+  ;;   1- replace the extension of the current file with .ali,
+  ;;      and look for this file
+  ;;   2- If this file is found:
+  ;;      grep the "^U" lines, and make sure we are not reading the
+  ;;      .ali file for a spec file. If we are, go to step 3.
+  ;;   3- If the file is not found or step 2 failed:
+  ;;      find the name of the "other file", ie the body, and look
+  ;;      for its associated .ali file by subtituing the extension
+
+  (save-excursion
+    (set-buffer (get-file-buffer file))
+    (let ((short-ali-file-name
+           (concat (file-name-sans-extension (file-name-nondirectory file))
+                   ".ali"))
+          (ali-file-name ""))
+      ;; First step
+      ;; we take the first possible completion
+      (setq ali-file-name (ada-find-ali-file-in-dir short-ali-file-name))
+
+      ;; If we have found the .ali file, but the source file was a spec
+      ;; with a non-standard name, search the .ali file for the body if any,
+      ;; since the xref information is more complete in that one
+      (unless ali-file-name
+	  (if (not (string= (file-name-extension file) ".ads"))
+	      (let ((is-spec nil)
+		    (specs ada-spec-suffixes)
+		    body-ali)
+		(while specs
+		  (if (string-match (concat (regexp-quote (car specs)) "$")
+				    file)
+		      (set 'is-spec t))
+		  (set 'specs (cdr specs)))
+
+		(if is-spec
+		    (set 'body-ali
+			 (ada-find-ali-file-in-dir
+			  (concat (file-name-sans-extension
+				   (file-name-nondirectory
+				    (ada-other-file-name)))
+				  ".ali"))))
+                (if body-ali
+                    (set 'ali-file-name body-ali))))
+	
+        ;;  else we did not find the .ali file
+        ;;  Second chance: in case the files do not have standard names (such
+        ;;  as for instance file_s.ada and file_b.ada), try to go to the
+        ;;  other file and look for its ali file
+        (setq short-ali-file-name
+              (concat (file-name-sans-extension
+		       (file-name-nondirectory (ada-other-file-name)))
+                      ".ali"))
+        (setq ali-file-name (ada-find-ali-file-in-dir short-ali-file-name))
+	
+        ;; If still not found, try to recompile the file
+        (if (not ali-file-name)
+            (progn
+              ;; recompile only if the user asked for this
+              (if ada-xref-create-ali
+                  (ada-xref-current file ali-file-name))
+              (error "Ali file not found. Recompile your file")))
+        )
+
+      ;; same if the .ali file is too old and we must recompile it
+      (if (and (file-newer-than-file-p file ali-file-name)
+               ada-xref-create-ali)
+          (ada-xref-current file ali-file-name))
+
+      ;; else returns the correct absolute file name
+      (expand-file-name ali-file-name))
+    ))
+
+(defun ada-get-ada-file-name (file original-file)
+  "Create the complete file name (+directory) for FILE
+The original file (where the user was) is ORIGINAL-FILE.
+Search in project file for possible paths"
+
+  (save-excursion
+    (set-buffer (get-file-buffer original-file))
+    ;; we choose the first possible completion and we
+    ;; return the absolute file name
+    (let ((filename
+           (ada-first-non-nil (mapcar (lambda (x)
+                          (if (file-exists-p (concat (file-name-directory x)
+                                                     (file-name-nondirectory file)))
+                              (concat (file-name-directory x)
+                                      (file-name-nondirectory file))
+                            nil))
+                        ada-prj-src-dir))))
+
+      (if filename
+          (expand-file-name filename)
+        (error (concat
+                (file-name-nondirectory file)
+                " not found in src_dir. Please check your project file")))
+
+      )))
+
+(defun ada-find-file-number-in-ali (file)
+  "Returns the file number for FILE in the associated ali file"
+  (set-buffer (ada-get-ali-buffer file))
+  (goto-char (point-min))
+
+  (let ((begin (re-search-forward "^D")))
+    (beginning-of-line)
+    (re-search-forward (concat "^D " (file-name-nondirectory file)))
+    (count-lines begin (point))))
+
+(defun ada-read-identifier (pos)
+  "Returns the identlist around POS and switch to the .ali buffer"
+
+  ;; If there's a compilation in progress, it's probably because the
+  ;; .ali file didn't exist. So we should wait...
+  (if compilation-in-progress
+      (progn
+        (message "Compilation in progress. Try again when it is finished")
+        (set 'quit-flag t)))
+
+  ;; If at end of buffer (e.g the buffer is empty), error
+  (if (>= (point) (point-max))
+      (error "No identifier on point"))
+  
+  ;; goto first character of the identifier/operator (skip backward < and >
+  ;; since they are part of multiple character operators
+  (goto-char pos)
+  (skip-chars-backward "a-zA-Z0-9_<>")
+
+  ;; check if it really is an identifier
+  (if (ada-in-comment-p)
+      (error "Inside comment"))
+
+  (let (identifier identlist)
+    ;; Just in front of a string => we could have an operator declaration,
+    ;; as in "+", "-", ..
+    (if (= (char-after) ?\")
+        (forward-char 1))
+
+    ;; if looking at an operator
+    (if (looking-at ada-operator-re)
+        (progn
+          (if (and (= (char-before) ?\")
+                   (= (char-after (+ (length (match-string 0)) (point))) ?\"))
+              (forward-char -1))
+          (set 'identifier (concat "\"" (match-string 0) "\"")))
+
+      (if (ada-in-string-p)
+          (error "Inside string or character constant"))
+      (if (looking-at (concat ada-keywords "[^a-zA-Z_]"))
+          (error "No cross-reference available for reserved keyword"))
+      (if (looking-at "[a-zA-Z0-9_]+")
+          (set 'identifier (match-string 0))
+        (error "No identifier around")))
+    
+    ;; Build the identlist
+    (set 'identlist    (ada-make-identlist))
+    (ada-set-name      identlist (downcase identifier))
+    (ada-set-line      identlist
+		       (number-to-string (count-lines (point-min) (point))))
+    (ada-set-column    identlist
+		       (number-to-string (1+ (current-column))))
+    (ada-set-file      identlist (buffer-file-name))
+    identlist
+    ))
+
+(defun ada-get-all-references (identlist)
+  "Completes and returns the identlist with the information extracted
+from the ali file (definition file and places where it is referenced)"
+  
+  (let ((ali-buffer (ada-get-ali-buffer (ada-file-of identlist)))
+	declaration-found)
+    (set-buffer ali-buffer)
+    (goto-char (point-min))
+    (ada-set-on-declaration identlist nil)
+
+    ;; First attempt: we might already be on the declaration of the identifier
+    ;; We want to look for the declaration only in a definite interval (after
+    ;; the "^X ..." line for the current file, and before the next "^X" line
+    
+    (if (re-search-forward
+	 (concat "^X [0-9]+ " (file-name-nondirectory (ada-file-of identlist)))
+	 nil t)
+        (let ((bound (save-excursion (re-search-forward "^X " nil t))))
+          (set 'declaration-found
+	       (re-search-forward
+		(concat "^"    (ada-line-of identlist)
+			"."    (ada-column-of identlist)
+			"[ *]" (regexp-quote (ada-name-of identlist))
+			" \\(.*\\)$") bound t))
+	  (if declaration-found
+	      (ada-set-on-declaration identlist t))
+	  ))
+
+    ;; If declaration is still nil, then we were not on a declaration, and
+    ;; have to fall back on other algorithms
+
+    (unless declaration-found
+      
+      ;; Since we alread know the number of the file, search for a direct
+      ;; reference to it
+      (goto-char (point-min))
+      (set 'declaration-found t)
+      (ada-set-ali-index
+       identlist
+       (number-to-string (ada-find-file-number-in-ali
+			  (ada-file-of identlist))))
+      (unless (re-search-forward (concat (ada-ali-index-of identlist)
+					 "|\\([0-9]+.[0-9]+ \\)*"
+					 (ada-line-of identlist)
+					 "[^0-9]"
+					 (ada-column-of identlist))
+				 nil t)
+
+          ;; if we did not find it, it may be because the first reference
+          ;; is not required to have a 'unit_number|' item included.
+          ;; Or maybe we are already on the declaration...
+          (unless (re-search-forward (concat "^\\([a-zA-Z0-9_.\"]+[ *]\\)*"
+					     (ada-line-of identlist)
+					     "[^0-9]"
+					     (ada-column-of identlist))
+				     nil t)
+	    
+	    ;; If still not found, then either the declaration is unknown
+	    ;; or the source file has been modified since the ali file was
+	    ;; created
+	    (set 'declaration-found nil)
+            )
+	  )
+
+      ;; Last check to be completly sure we have found the correct line (the
+      ;; ali might not be up to date for instance)
+      (if declaration-found
+	  (progn
+	    (beginning-of-line)
+	    ;; while we have a continuation line, go up one line
+	    (while (looking-at "^\\.")
+	      (previous-line 1))
+	    (unless (looking-at (concat "[0-9]+.[0-9]+[ *]"
+					(ada-name-of identlist) " "))
+	      (set 'declaration-found nil))))
+
+      ;; Still no success ! The ali file must be too old, and we need to
+      ;; use a basic algorithm based on guesses. Note that this only happens
+      ;; if the user does not want us to automatically recompile files
+      ;; automatically
+      (unless declaration-found
+	(unless (ada-xref-find-in-modified-ali identlist)
+	  ;; no more idea to find the declaration. Give up
+	  (progn
+	    (kill-buffer ali-buffer)
+	    (error (concat "No declaration of " (ada-name-of identlist)
+			   " found."))
+	    )))
+      )
+
+    
+    ;; Now that we have found a suitable line in the .ali file, get the
+    ;; information available
+    (beginning-of-line)
+    (if declaration-found
+        (let ((current-line (buffer-substring
+			     (point) (save-excursion (end-of-line) (point)))))
+          (save-excursion
+            (next-line 1)
+            (beginning-of-line)
+            (while (looking-at "^\\.\\(.*\\)")
+              (set 'current-line (concat current-line (match-string 1)))
+              (next-line 1))
+            )
+
+	  (if (re-search-backward "^X [0-9]+ \\([a-zA-Z0-9_.-]+\\)" nil t)
+	      (ada-set-declare-file
+	       identlist
+	       (ada-get-ada-file-name (match-string 1)
+				      (ada-file-of identlist))))
+	  
+	  (ada-set-references   identlist current-line)
+	  ))
+  ))
+
+(defun ada-xref-find-in-modified-ali (identlist)
+  "Find the matching position for IDENTLIST in the current ali buffer.
+This function is only called when the file was not up-to-date, so we need
+to make some guesses.
+This function is disabled for operators, and only works for identifiers"
+
+  (unless (= (string-to-char (ada-name-of identlist)) ?\")
+      (progn
+        (let ((declist '()) ;;; ( (line_in_ali_file line_in_ada) ( ... ))
+	      (my-regexp  (concat "[ *]"
+				  (regexp-quote (ada-name-of identlist)) " "))
+	      (line-ada "--")
+	      (col-ada  "--")
+	      (line-ali 0)
+	      (len 0)
+	      (choice 0))
+
+          (goto-char (point-max))
+          (while (re-search-backward my-regexp nil t)
+            (save-excursion
+              (set 'line-ali (count-lines (point-min) (point)))
+              (beginning-of-line)
+              ;; have a look at the line and column numbers
+              (if (looking-at "^\\([0-9]+\\).\\([0-9]+\\)[ *]")
+                  (progn
+                    (setq line-ada (match-string 1))
+                    (setq col-ada  (match-string 2)))
+                (setq line-ada "--")
+                (setq col-ada  "--")
+                )
+              ;; construct a list with the file names and the positions within
+              (if (re-search-backward "^X [0-9]+ \\([a-zA-Z0-9._-]+\\)" nil t)
+		  (add-to-list
+		   'declist (list line-ali (match-string 1) line-ada col-ada))
+                )
+              )
+            )
+
+          ;; how many possible declarations have we found ?
+          (setq len (length declist))
+          (cond
+           ;; none => error
+           ((= len 0)
+            (kill-buffer (current-buffer))
+            (error (concat "No declaration of "
+                           (ada-name-of identlist)
+                           " recorded in .ali file")))
+	   
+           ;; one => should be the right one
+           ((= len 1)
+            (goto-line (caar declist)))
+	   
+           ;; more than one => display choice list
+           (t
+            (with-output-to-temp-buffer "*choice list*"
+
+              (princ "Identifier is overloaded and Xref information is not up to date.\n")
+              (princ "Possible declarations are:\n\n")
+              (princ "  no.   in file                at line  col\n")
+              (princ "  ---   ---------------------     ----  ----\n")
+              (let ((counter 1))
+                (while (<= counter len)
+                  (princ (format "  %2d)    %-21s   %4s  %4s\n"
+                                 counter
+				 (ada-get-ada-file-name
+				  (nth 1 (nth (1- counter) declist))
+				  (ada-file-of identlist))
+                                 (nth 2 (nth (1- counter) declist))
+                                 (nth 3 (nth (1- counter) declist))
+                                 ))
+                  (setq counter (1+ counter))
+                  ) ; end of while
+                ) ; end of let
+              ) ; end of with-output-to ...
+            (setq choice nil)
+            (while (or
+                    (not choice)
+                    (not (integerp choice))
+                    (< choice 1)
+                    (> choice len))
+              (setq choice (string-to-int
+                            (read-from-minibuffer "Enter No. of your choice: "))))
+            (goto-line (car (nth (1- choice) declist)))
+            ))))))
+
+
+(defun ada-find-in-ali (identlist &optional other-frame)
+  "Look in the .ali file for the definition of the identifier
+if OTHER-FRAME is non nil, and `ada-xref-other-buffer' is non nil,
+opens a new window to show the declaration"
+
+  (ada-get-all-references identlist)
+  (let ((ali-line (ada-references-of identlist))
+	file  line  col)
+    
+    ;; If we were on a declaration, go to the body
+    (if (ada-on-declaration identlist)
+	(if (string-match "\\([0-9]+\\)[bc]\\([0-9]+\\)" ali-line)
+	    (progn
+	      (setq line (match-string 1 ali-line)
+		    col  (match-string 2 ali-line))
+	      ;;  it there was a file number in the same line
+	      (if (string-match "\\([0-9]+\\)|\\([^|bc]+\\)?[bc]" ali-line)
+		  (let ((file-number (match-string 1 ali-line)))
+		    (goto-char (point-min))
+		    (re-search-forward "^D \\([a-zA-Z0-9_.-]+\\)" nil t
+				       (string-to-number file-number))
+		    (set 'file (match-string 1))
+		    )
+		;; Else get the nearest file
+		(re-search-backward "^X [0-9]+ \\([a-zA-Z0-9_.-]+\\)" nil t)
+		(set 'file (match-string 1))
+		)
+	      )
+	  (error "No body found"))
+    
+      ;; Else we were not on the declaration, find the place for it
+      (string-match "\\([0-9]+\\)[a-zA-Z+]\\([0-9]+\\)[ *]" ali-line)
+      (setq line (match-string 1 ali-line)
+	    col  (match-string 2 ali-line)
+	    file (ada-declare-file-of identlist))
+      )
+
+    ;; Now go to the buffer
+    (ada-xref-change-buffer
+     (ada-get-ada-file-name file (ada-file-of identlist))
+     (string-to-number line)
+     (1- (string-to-number col))
+     identlist
+     other-frame)
+    ))
+
+(defun ada-xref-change-buffer
+  (file line column identlist &optional other-frame)
+  "Select and display FILE, at LINE and COLUMN. The new file is
+associated with the same project file as the one for IDENTLIST.
+If we do not end on the same identifier as IDENTLIST, find the closest
+match. Kills the .ali buffer at the end"
+
+  (let (prj-file
+        declaration-buffer
+	(ali-buffer (current-buffer)))
+
+    ;; get the current project file for the source ada file
+    (save-excursion
+      (set-buffer (get-file-buffer (ada-file-of identlist)))
+      (set 'prj-file ada-prj-prj-file))
+
+    ;; Select and display the destination buffer
+    (if ada-xref-other-buffer
+        (if other-frame
+            (find-file-other-frame file)
+          (set 'declaration-buffer (find-file-noselect file))
+          (set-buffer declaration-buffer)
+          (switch-to-buffer-other-window declaration-buffer)
+          )
+      (find-file file)
+      )
+
+    ;; If the new buffer is not already associated with a project file, do it
+    (unless (my-local-variable-if-set-p 'ada-prj-prj-file (current-buffer))
+        (progn
+          (make-local-variable 'ada-prj-prj-file)
+          (set 'ada-prj-prj-file prj-file)))
+
+    ;; move the cursor to the correct position
+    (push-mark)
+    (goto-line line)
+    (move-to-column column)
+
+    ;; If we are not on the identifier, the ali file was not up-to-date.
+    ;; Try to find the nearest position where the identifier is found,
+    ;; this is probably the right one.
+    (unless (looking-at (ada-name-of identlist))
+      (ada-xref-search-nearest (ada-name-of identlist)))
+
+    (kill-buffer ali-buffer)))
+
+
+(defun ada-xref-search-nearest (name)
+  "Searches for NAME nearest to the position recorded in the Xref file.
+It returns the position of the declaration in the buffer or nil if not found."
+  (let ((orgpos (point))
+        (newpos nil)
+        (diff nil))
+
+    (goto-char (point-max))
+
+    ;; loop - look for all declarations of name in this file
+    (while (search-backward name nil t)
+
+      ;; check if it really is a complete Ada identifier
+      (if (and
+           (not (save-excursion
+                  (goto-char (match-end 0))
+                  (looking-at "_")))
+           (not (ada-in-string-or-comment-p))
+           (or
+            ;; variable declaration ?
+            (save-excursion
+              (skip-chars-forward "a-zA-Z_0-9" )
+              (ada-goto-next-non-ws)
+              (looking-at ":[^=]"))
+            ;; procedure, function, task or package declaration ?
+            (save-excursion
+              (ada-goto-previous-word)
+              (looking-at "\\<[pP][rR][oO][cC][eE][dD][uU][rR][eE]\\>\\|\\<[fF][uU][nN][cC][tT][iI][oO][nN]\\>\\|\\<[tT][yY][pP][eE]\\>\\|\\<[tT][aA][sS][kK]\\>\\|\\<[pP][aA][cC][kK][aA][gG][eE]\\>\\|\\<[bB][oO][dD][yY]\\>"))))
+
+          ;; check if it is nearer than the ones before if any
+          (if (or (not diff)
+                  (< (abs (- (point) orgpos)) diff))
+              (progn
+                (setq newpos (point)
+		      diff (abs (- newpos orgpos))))))
+      )
+
+    (if newpos
+        (progn
+          (message "ATTENTION: this declaration is only a (good) guess ...")
+          (goto-char newpos))
+      nil)))
+
+
+;; Find the parent library file of the current file
+(defun ada-goto-parent ()
+  "go to the parent library file"
+  (interactive)
+  (ada-require-project-file)
+
+  (let ((buffer (ada-get-ali-buffer (buffer-file-name)))
+        (unit-name nil)
+        (body-name nil)
+        (ali-name nil))
+    (save-excursion
+      (set-buffer buffer)
+      (goto-char (point-min))
+      (re-search-forward "^U \\([^ \t%]+\\)%[bs][ \t]+\\([^ \t]+\\)")
+      (setq unit-name (match-string 1))
+      (if (not (string-match "\\(.*\\)\\.[^.]+" unit-name))
+          (progn
+            (kill-buffer buffer)
+            (error "No parent unit !"))
+        (setq unit-name (match-string 1 unit-name))
+        )
+
+      ;; look for the file name for the parent unit specification
+      (goto-char (point-min))
+      (re-search-forward (concat "^W " unit-name
+                                 "%s[ \t]+\\([^ \t]+\\)[ \t]+"
+                                 "\\([^ \t\n]+\\)"))
+      (setq body-name (match-string 1))
+      (setq ali-name (match-string 2))
+      (kill-buffer buffer)
+      )
+
+    (setq ali-name (ada-find-ali-file-in-dir ali-name))
+
+    (save-excursion
+      ;; Tries to open the new ali file to find the spec file
+      (if ali-name
+          (progn
+            (find-file ali-name)
+            (goto-char (point-min))
+            (re-search-forward (concat "^U " unit-name "%s[ \t]+"
+                                       "\\([^ \t]+\\)"))
+            (setq body-name (match-string 1))
+            (kill-buffer (current-buffer))
+            )
+        )
+      )
+
+    (find-file body-name)
+    ))
+
+(defun ada-make-filename-from-adaname (adaname)
+  "Determine the filename of a package/procedure from its own Ada name."
+  ;; this is done simply by calling `gnatkr', when we work with GNAT. It
+  ;; must be a more complex function in other compiler environments.
+  (let (krunch-buf)
+    (setq krunch-buf (generate-new-buffer "*gkrunch*"))
+    (save-excursion
+      (set-buffer krunch-buf)
+      ;; send adaname to external process `gnatkr'.
+      (call-process "gnatkr" nil krunch-buf nil
+                    adaname ada-krunch-args)
+      ;; fetch output of that process
+      (setq adaname (buffer-substring
+                     (point-min)
+                     (progn
+                       (goto-char (point-min))
+                       (end-of-line)
+                       (point))))
+      (kill-buffer krunch-buf)))
+  adaname
+  )
+
+
+(defun ada-make-body-gnatstub ()
+  "Create an Ada package body in the current buffer.
+This function uses the `gnatstub' program to create the body.
+This function typically is to be hooked into `ff-file-created-hooks'."
+  (interactive)
+
+  (save-some-buffers nil nil)
+
+  (ada-require-project-file)
+
+  (delete-region (point-min) (point-max))
+
+  ;; Call the external process gnatstub
+  (let* ((gnatstub-opts (ada-treat-cmd-string ada-gnatstub-opts))
+         (filename      (buffer-file-name (car (cdr (buffer-list)))))
+         (output        (concat (file-name-sans-extension filename) ".adb"))
+         (gnatstub-cmd  (concat "gnatstub " gnatstub-opts " " filename))
+         (buffer        (get-buffer-create "*gnatstub*")))
+
+    (save-excursion
+      (set-buffer buffer)
+      (compilation-minor-mode 1)
+      (erase-buffer)
+      (insert gnatstub-cmd)
+      (newline)
+      )
+    ;; call gnatstub to create the body file
+    (call-process shell-file-name nil buffer nil "-c" gnatstub-cmd)
+
+    (if (save-excursion
+          (set-buffer buffer)
+          (goto-char (point-min))
+          (search-forward "command not found" nil t))
+        (progn
+          (message "gnatstub was not found -- using the basic algorithm")
+          (sleep-for 2)
+          (kill-buffer buffer)
+          (ada-make-body))
+
+      ;; Else clean up the output
+
+      ;;  Kill the temporary buffer created by find-file
+      (set-buffer-modified-p nil)
+      (kill-buffer (current-buffer))
+
+      (if (file-exists-p output)
+          (progn
+            (find-file output)
+            (kill-buffer buffer))
+
+        ;; display the error buffer
+        (display-buffer buffer)
+        )
+      )))
+
+
+(defun ada-xref-initialize ()
+  "Function called by ada-mode-hook to initialize the ada-xref.el package.
+For instance, it creates the gnat-specific menus, set some hooks for
+find-file...."
+  (ada-add-ada-menu)
+  (make-local-hook 'ff-file-created-hooks)
+  (setq ff-file-created-hooks 'ada-make-body-gnatstub)
+
+  ;; Read the project file and update the search path
+  ;; before looking for the other file
+  (make-local-hook 'ff-pre-find-hooks)
+  (add-hook 'ff-pre-find-hooks 'ada-require-project-file)
+
+  ;; Completion for file names in the mini buffer should ignore .ali files
+  (add-to-list 'completion-ignored-extensions ".ali")
+  )
+
+
+;; ----- Add to ada-mode-hook ---------------------------------------------
+
+;;  Set the keymap once and for all, so that the keys set by the user in his
+;;  config file are not overwritten every time we open a new file.
+(ada-add-keymap)
+
+(add-hook 'ada-mode-hook 'ada-xref-initialize)
+
+(provide 'ada-xref)
+
+;;; ada-xref.el ends here