Go to the previous, next section.

 lengths-list-file in Detail

The core of the  lengths-list-file function is a  while loop containing a function to move point forward `defun by defun' and a function to count the number of words and symbols in each defun. This core must be surrounded by functions that do various other tasks, including finding the file, and ensuring that point starts out at the beginning of the file. The function definition looks like this:

(defun lengths-list-file (filename)
  "Return list of definitions' lengths within FILE.
The returned list is a list of numbers.
Each number is the number of words or
symbols in one function definition."
  (message "Working on `%s' ... " filename)
  (save-excursion
    (let ((buffer (find-file-noselect filename))
          (lengths-list))
      (set-buffer buffer)
      (setq buffer-read-only t)
      (widen)   
      (goto-char (point-min))
      (while (re-search-forward "^(defun" nil t)
        (setq lengths-list
              (cons (count-words-in-defun) lengths-list)))
      (kill-buffer buffer)
      lengths-list)))

The function is passed one argument, the name of the file on which it will work. It has four lines of documentation, but no interactive specification. Since people worry that a computer is broken if they don't see anything going on, the first line of the body is a message.

The next line contains a  save-excursion that returns Emacs attention to the current buffer when the function completes. This is useful in case you embed this function in another function that presumes point is restored to the original buffer.

In the varlist of the  let expression, Emacs finds the file and binds the local variable  buffer to the buffer containing the file. At the same time, Emacs creates  lengths-list as a local variable.

Next, Emacs switches its attention to the buffer.

In the following line, Emacs makes the buffer read-only. Ideally, this line is not necessary. None of the functions for counting words and symbols in a function definition should change the buffer. Besides, the buffer is not going to be saved, even if it were changed. This line is entirely the consequence of great, perhaps excessive, caution. The reason for the caution is that this function and those it calls work on the sources for Emacs and it is very inconvenient if they are inadvertently modified. It goes without saying that I did not realize a need for this line until an experiment went awry and started to modify my Emacs source files @dots{}

Next comes a call to widen the buffer if it is narrowed. This function is usually not needed--Emacs creates a fresh buffer if none already exists; but if a buffer visiting the file already exists Emacs returns that one. In this case, the buffer may be narrowed and must be widened. If we wanted to be fully `user-friendly', we would arrange to save the restriction and the location of point, but we won't.

The  (goto-char (point-min)) expression moves point to the beginning of the buffer.

Then comes a  while loop in which the `work' of the function is carried out. In the loop, Emacs determines the length of each definition and constructs a lengths' list containing the information.

Emacs kills the buffer after working through it. This is to save space inside of Emacs. My version of Emacs 19 contains over 300 source files of interest. Another function will apply  lengths-list-file to each of them. If Emacs visits all of them and deletes none, my computer may run out of virtual memory.

Finally, the last expression within the  let expression is the  lengths-list variable; its value is returned as the value of the whole function.

You can try this function by installing it in the usual fashion. Then place your cursor after the following expression and type C-x C-e ( eval-last-sexp ).

(lengths-list-file "../lisp/debug.el")

(You may need to change the pathname of the file; the one here works if this Info file and the Emacs sources are in neighboring places, such as  /usr/local/emacs/info and  /usr/local/emacs/lisp . To change the expression, copy it to the `*scratch*' buffer and edit it. Then evaluate it.)

On my version of Emacs, the lengths' list for `debug.el' takes seven seconds to produce and looks like this:

(75 41 80 62 20 45 44 68 45 12 34 235)

Note that the length of the last definition in the file is first in the list.

Go to the previous, next section.