1 ;;; semanticdb-system.el --- Build a file DB for some system files.
3 ;;; Copyright (C) 2002, 2003, 2004, 2005 Eric M. Ludlam
5 ;; Author: Eric M. Ludlam <zappo@gnu.org>
7 ;; X-RCS: $Id: semanticdb-system.el,v 1.1 2007-11-26 15:10:48 michaels Exp $
9 ;; This file is not part of GNU Emacs.
11 ;; Semanticdb is free software; you can redistribute it and/or modify
12 ;; it under the terms of the GNU General Public License as published by
13 ;; the Free Software Foundation; either version 2, or (at your option)
16 ;; This software is distributed in the hope that it will be useful,
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 ;; GNU General Public License for more details.
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with GNU Emacs; see the file COPYING. If not, write to the
23 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24 ;; Boston, MA 02110-1301, USA.
28 ;; A system database is a file based DB which contains tags from a
29 ;; system. These files are ONLY ever loaded in, and can only be written
30 ;; using a set of user initiated scripts.
33 (require 'semanticdb-file)
37 (defcustom semanticdb-default-system-save-directory
38 ;; Leave this obvious for now. Maybe hide it later.
39 (expand-file-name "~/.semanticdb")
40 "*Directory name where semantic cache files for system headers are stored.
41 System files cannot have caches stored near them because users rarely have
42 write permission to such paths."
44 :type '(choice :tag "System-Save-Directory"
45 :menu-tag "System-Save-Directory"
46 (const :tag "Use current directory" :value nil)
49 (defcustom semanticdb-system-database-warn-level 50
50 "*Number of files to be added to a system DB that causes us to warn.
51 If this number is exceeded, warn the users that it could take a while."
55 (defvar semanticdb-system-force-save nil
56 "When non-nil, the system DB will save itself.
57 Do not set this to non-nil unless you building a system table for
60 (defvar semanticdb-database-being-created nil
61 "Database currently being created.")
64 (defclass semanticdb-project-database-system (semanticdb-project-database-file)
65 ((file-header-line :initform
66 ";; SEMANTICDB Tags save file for system libraries")
67 (file-match-regex :allocation :class
70 "Regular expression used to match files names for this database.
71 When building new databases, only matching files will be included.")
72 (major-modes :allocation :class
75 "List of major modes this database is useful to.
76 Thus, C header files are useful to `c-mode', and to `c++-mode'.")
77 ;; Provide an init arg for this item so that it will
78 ;; be saved in the file.
79 (reference-directory :initarg :reference-directory)
81 "Database of file tables for system libraries saved to disk."
84 (defmethod semanticdb-create-database :STATIC ((dbc semanticdb-project-database-system)
86 "Create a new semantic database for DIRECTORY and return it.
87 If a database for DIRECTORY has already been loaded, return it.
88 If a database for DIRECTORY exists, then load that database, and return it.
89 If DIRECTORY doesn't exist, create a new one."
90 ;; System databases span directories. Be smart about creation.
91 (or semanticdb-database-being-created
94 (defmethod semanticdb-write-directory-p
95 ((obj semanticdb-project-database-system))
96 "Return non-nil if OBJ should be written to disk.
97 Uses `semanticdb-persistent-path' to determine the return value."
98 semanticdb-system-force-save)
100 (defmethod semanticdb-cache-filename :STATIC
101 ((dbclass semanticdb-project-database-system) path)
102 "For DBCLASS, return a file to a cache file belonging to PATH.
103 This could be a cache file in the current directory, or an encoded file
104 name in a secondary directory."
105 ;; This variable hack re-uses logic for file based databases.
106 ;; Not too purty, but ok for now.
107 (let ((semanticdb-default-save-directory
108 semanticdb-default-system-save-directory))
111 ;;; User initialization
113 (defvar semanticdb-system-database-query-history nil
114 "History variable when asking for a type of system database.")
117 (defun semanticdb-create-system-database (path &optional class)
118 "Create a system database starting at PATH.
119 PATH should be a top level directory for a series of files containing
120 declarations for SYSTEM files. In C, this would be header filaes.
121 CLASS is the class for the database to create. Only child classes
122 of symbol `semanticdb-project-database-system' are accepted."
123 (interactive "DPath to system files: ")
124 ;; Make sure there is a / at the end.
125 (setq path (semanticdb-fix-pathname path))
126 ;; Make sure storage is available
127 (if (not semanticdb-default-system-save-directory)
128 (if (y-or-n-p "Specify value for system database storage now? ")
129 (customize-variable 'semanticdb-default-system-save-directory)
131 ;; Get a dir if needed
132 (if (not (file-exists-p semanticdb-default-system-save-directory))
134 (format "Create %s now? " semanticdb-default-system-save-directory))
135 (make-directory semanticdb-default-system-save-directory)
137 ;; All set with that path. Ask about system type.
141 (eieio-read-subclass "System Type: "
142 semanticdb-project-database-system
143 'semanticdb-system-database-query-history
145 (signal 'wrong-type-argument '(class nil))))
146 (if (not (child-of-class-p class semanticdb-project-database-system))
147 (signal 'wrong-type-argument (list 'class class)))
149 (semanticdb-load-system-database class path)
153 (defun semanticdb-load-system-caches ()
154 "Load all system databases that were previously saved."
156 (let ((f (directory-files semanticdb-default-system-save-directory
157 t (concat semanticdb-default-file-name "$") t)))
159 ;; Emacs makes backup files if we save out the systemDB too often.
160 ;; prevent loading backup files which are icky.
161 (when (string-match (concat semanticdb-default-file-name "$")
163 (semanticdb-load-database (car f)))
164 ;; NOTE FOR THE FUTURE: Verify the system was not expanded for
165 ;; each. This may be slow.
169 (defvar semanticdb-system-db-directory-search-recursed nil
170 "Track if we recursed for directory files.")
172 (defmethod semanticdb-load-system-database :STATIC
173 ((dbclass semanticdb-project-database-system) path)
174 "Load a system database of type DBCLASS starting at PATH.
175 PATH should be a top level directory for a series of files containing
176 declarations for SYSTEM files. In C, this would be header files.
177 Only files in PATH matching DBCLASS' regular expression will be loaded
178 and parsed. After the database is created, save it, and return the DB."
179 ;; For each file do the following:
180 ;; 1) If already in database, skip
181 ;; 2) Setup semanticdb files to make sure new table shows up
182 ;; in the system database
183 ;; 3) Load the file. Allow normal semantic initialization.
184 ;; 4) Force a reparse.
185 ;; 5) Kill file if it wasn't already in a buffer.
186 (let* ((semanticdb-system-db-directory-search-recursed nil)
187 (files (semanticdb-collect-matching-filenames
188 path (oref-default dbclass file-match-regex)))
189 (sysdb (semanticdb-create-database dbclass path))
190 ;; 2) Set up to use this database when loading.
191 (semanticdb-new-database-class dbclass)
193 (if (and (> (length files) semanticdb-system-database-warn-level)
194 semanticdb-system-db-directory-search-recursed
197 "%d files found. Try again without scanning subdirectories? "
199 (setq files (semanticdb-collect-matching-filenames
200 path (oref-default dbclass file-match-regex) t)))
201 (when (> (length files) semanticdb-system-database-warn-level)
204 "There are %d files which could a long time to parse. Proceed? "
208 (oset sysdb reference-directory path)
210 (let ((table (semanticdb-file-table sysdb (car files)))
213 (unless (and table (oref table tags))
215 (let ((b (get-file-buffer (car files))))
217 (set-buffer (find-file-noselect (car files)))
218 ;; 4) Force a reparse
219 (semantic-fetch-tags)
220 ;; At this point, standard semantic actions
222 ;; 5) Kill the buffer
223 (if (not b) (kill-buffer (current-buffer)))))
225 (setq files (cdr files)))
227 ;; All tables are in. Save this database
228 (let ((semanticdb-system-force-save t))
229 (semanticdb-save-db sysdb))
231 ;; Add it to the search path for major modes.
232 (let ((m (oref-default sysdb major-modes)))
234 (let ((v (mode-local-value (car m) 'semanticdb-project-system-databases))
236 (setq v (cons sysdb v))
237 ;; NOTE TO SELF; get a set version of `setq-mode-local'.
238 (eval `(setq-mode-local ,(car m)
239 semanticdb-project-system-databases v)))
245 (defun semanticdb-collect-matching-filenames (path regexp &optional not-recursive)
246 "Collect a list of all filenames starting at PATH matching REGEXP.
247 Optional argument NOT-RECURSIVE suggests that this function will not recurse."
248 (let ((returnfiles nil)
251 (useregexp (concat "^[^.].*" regexp)))
254 ;; First, look for more subdirectories.
255 (when (not not-recursive)
256 (setq files (directory-files (car dirs) t "^[^.]" t))
258 (let ((attr (file-attributes (car files))))
259 ;; String in (car attr) is a symlink.
260 (if (and attr (car attr) (not (stringp (car attr))))
261 (setq dirs (append dirs (list (car files)))
262 semanticdb-system-db-directory-search-recursed t))
263 (setq files (cdr files)))))
265 ;; Now get the list of files we are returning.
267 (append returnfiles (directory-files (car dirs) t useregexp nil)))
269 (setq dirs (cdr dirs)))
272 ;;; Here are a a couple implementations
274 (defclass semanticdb-project-database-system-c (semanticdb-project-database-system)
275 ((file-header-line :initform
276 ";; SEMANTICDB Tags save file for system libraries")
277 ;; Scan for C header files.
278 (file-match-regex :initform "\\.\\(h\\(h\\|xx\\|pp\\|\\+\\+\\)?\\|H\\)?$")
280 (major-modes :initform '(c-mode c++-mode))
282 "Database of file tables for system libraries saved to disk.")
285 (provide 'semanticdb-system)
287 ;;; semanticdb-system.el ends here