Commits

Anonymous committed 44f74d2

Created

Comments (0)

Files changed (9)

+1998-01-12  SL Baur  <steve@altair.xemacs.org>
+
+	* Makefile: Update to newer package interface.
+
+1998-01-03  SL Baur  <steve@altair.xemacs.org>
+
+	* Makefile: Update to newer package interface.
+
+1997-12-29  SL Baur  <steve@altair.xemacs.org>
+
+	* Makefile: Created.
+# Makefile for Miscellaneous C Support lisp code
+
+# This file is part of XEmacs.
+
+# XEmacs 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.
+
+# XEmacs 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 XEmacs; see the file COPYING.  If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+# This XEmacs package contains independent single file lisp packages
+
+VERSION = 1.02
+PACKAGE = c-support
+PKG_TYPE = single-file
+REQUIRES = cc-mode xemacs-base
+CATEGORY = prog
+
+ELCS = c-comment.elc c-fill.elc c-style.elc cmacexp.elc hideif.elc \
+	hideshow.elc
+
+include ../../XEmacs.rules
+
+all:: $(ELCS) auto-autoloads.elc custom-load.elc
+
+srckit: srckit-std
+
+binkit: binkit-sourceonly
+;;; c-comment.el --- edit C comments
+
+;; Copyright (C) 1987, 1988, 1989 Kyle E. Jones
+;; Copyright (C) 1997 Free Software Foundation, Inc.
+
+;; Author: Kyle Jones <kyle_jones@wonderworks.com>
+;; Maintainer: XEmacs Development Team
+;; Keywords: languages
+
+;; This file is part of XEmacs.
+
+;; XEmacs 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.
+
+;; XEmacs 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 XEmacs; see the file COPYING.  If not, write to
+;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Synched up with: Not in FSF.
+
+;;; Commentary:
+
+;;
+;; Verbatim copies of this file may be freely redistributed.
+;;
+;; Modified versions of this file may be redistributed provided that this
+;; notice remains unchanged, the file contains prominent notice of
+;; author and time of modifications, and redistribution of the file
+;; is not further restricted in any way.
+;;
+;; This file is distributed `as is', without warranties of any kind.
+
+;; sb [23-Oct-1997] Put into standard format, fixed an autoload cookie.
+
+;;; Code:
+
+(provide 'c-comment-edit)
+
+(defvar c-comment-leader " *"
+  "*Leader used when rebuilding edited C comments.  The value of this variable
+should be a two-character string.  Values of \"  \", \" *\" and \"**\" produce the
+comment styles:
+	/*	/*	/*
+	  ...	 * ...	** ...
+	  ...	 * ...	** ...
+	*/	 */	*/
+respectively.")
+
+(defconst c-comment-leader-regexp "^[ 	]*\\(\\*\\*\\|\\*\\)?[ ]?"
+  "Regexp used to match C comment leaders.")
+
+(defvar c-comment-edit-mode 'text-mode
+  "*Major mode used by `c-comment-edit' when editing C comments.")
+
+(defvar c-comment-edit-hook nil
+  "*Function to call whenever `c-comment-edit' is used.
+The function is called just before the `c-comment-edit' function allows you to
+begin editing the comment.")
+
+(defvar c-comment-edit-buffer-alist nil
+  "Assoc list of C buffers and their associated comment buffers.
+Elements are of the form (C-BUFFER COMMENT-BUFFER COMMENT-START COMMENT-END)
+COMMENT-START and COMMENT-END are markers in the C-BUFFER.")
+
+(defmacro save-point (&rest body)
+  "Save value of point, evalutes FORMS and restore value of point.
+If the saved value of point is no longer valid go to (point-max).
+The variable `save-point' is lambda-bound to the value of point for
+the duration of this call."
+  (list 'let '((save-point (point)))
+	(list 'unwind-protect
+	      (cons 'progn body)
+	      '(goto-char (min (point-max) save-point)))))
+
+(defmacro marker (pos &optional buffer)
+  (list 'set-marker '(make-marker) pos buffer))
+
+(defvar c-comment-edit-map nil "Key map for c-comment-edit buffers")
+(if c-comment-edit-map
+    nil
+  (setq c-comment-edit-map (make-sparse-keymap))
+  (define-key c-comment-edit-map [(meta control c)] 'c-comment-edit-end)
+  (define-key c-comment-edit-map [(control c) (control c)] 'c-comment-edit-end)
+  (define-key c-comment-edit-map [(control c) (control ?\])] 'c-comment-edit-abort))
+
+;;;###autoload
+(defun c-comment-edit (search-prefix)
+  "Edit multi-line C comments.
+This command allows the easy editing of a multi-line C comment like this:
+   /*
+    * ...
+    * ...
+    */
+The comment may be indented or flush with the left margin.
+
+If point is within a comment, that comment is used.  Otherwise the
+comment to be edited is found by searching forward from point.
+
+With one \\[universal-argument] searching starts after moving back one
+  paragraph.
+With two \\[universal-argument]'s searching starts at the beginning of the
+  current or proceeding C function.
+With three \\[universal-argument]'s searching starts at the beginning of the
+  current page.
+With four \\[universal-argument]'s searching starts at the beginning of the
+  current buffer (clipping restrictions apply).
+
+Once located, the comment is copied into a temporary buffer, the comment
+leaders and delimiters are stripped away and the resulting buffer is
+selected for editing.  The major mode of this buffer is controlled by
+the variable `c-comment-edit-mode'.\\<c-comment-edit-map>
+
+Use \\[c-comment-edit-end] when you have finished editing the comment.  The
+comment will be inserted into the original buffer with the appropriate
+delimiters and indention, replacing the old version of the comment.  If
+you don't want your edited version of the comment to replace the
+original, use \\[c-comment-edit-abort]." 
+  (interactive "*P")
+  (let ((c-buffer (current-buffer))
+	marker tem c-comment-fill-column c-comment-buffer
+	c-comment-start c-comment-end
+	(inhibit-quit t))
+    ;; honor search-prefix
+    (cond ((equal search-prefix '(4))
+	   (backward-paragraph))
+	  ((equal search-prefix '(16))
+	   (end-of-defun)
+	   (beginning-of-defun)
+	   (backward-paragraph))
+	  ((equal search-prefix '(64))
+	   (backward-page))
+	  ((equal search-prefix '(256))
+	   (goto-char (point-min))))
+    (if (and (null search-prefix) (setq tem (within-c-comment-p)))
+	(setq c-comment-start (marker (car tem))
+	      c-comment-end (marker (cdr tem)))
+      (let (start end)
+	(condition-case error-data
+	    (save-point
+	      (search-forward "/*")
+	      (setq start (- (point) 2))
+	      (search-forward "*/")
+	      (setq end (point)))
+	  (search-failed (error "No C comment found.")))
+	(setq c-comment-start (marker start))
+	(setq c-comment-end (marker end))))
+    ;; calculate the correct fill-column for the comment
+    (setq c-comment-fill-column (- fill-column
+				   (save-excursion
+				     (goto-char c-comment-start)
+				     (current-column))))
+    ;; create the comment buffer
+    (setq c-comment-buffer
+	  (generate-new-buffer (concat (buffer-name) " *C Comment Edit*")))
+    ;; link into the c-comment-edit-buffer-alist
+    (setq c-comment-edit-buffer-alist
+	  (cons (list (current-buffer) c-comment-buffer
+		      c-comment-start c-comment-end)
+		c-comment-edit-buffer-alist))
+    ;; copy to the comment to the comment-edit buffer
+    (copy-to-buffer c-comment-buffer (+ c-comment-start 2) (- c-comment-end 2))
+    ;; mark the position of point, relative to the beginning of the
+    ;; comment, in the comment buffer.  (iff point is within a comment.)
+    (or search-prefix (< (point) c-comment-start)
+	(setq marker (marker (+ (- (point) c-comment-start 2) 1)
+			     c-comment-buffer)))
+    ;; select the comment buffer for editing
+    (switch-to-buffer c-comment-buffer)
+    ;; remove the comment leaders and delimiters
+    (goto-char (point-min))
+    (while (not (eobp))
+      (and (re-search-forward c-comment-leader-regexp nil t)
+	   (replace-match "" nil t))
+      (forward-line))
+    ;; run appropriate major mode
+    (funcall (or c-comment-edit-mode 'fundamental-mode))
+    ;; override user's default fill-column here since it will lose if
+    ;; the comment is indented in the C buffer.
+    (setq fill-column c-comment-fill-column)
+    ;; delete one leading whitespace char
+    (goto-char (point-min))
+    (if (looking-at "[ \n\t]")
+	(delete-char 1))
+    ;; restore cursor if possible
+    (goto-char (or marker (point-min)))
+    (set-buffer-modified-p nil)
+    (use-local-map c-comment-edit-map c-comment-buffer))
+  ;; run user hook, if present.
+  (if c-comment-edit-hook
+      (funcall c-comment-edit-hook))
+  ;; final admonition
+  (message
+   (substitute-command-keys
+    "Type \\[c-comment-edit-end] to end edit, \\[c-comment-edit-abort] to abort with no change.")))
+
+(defun c-comment-edit-end ()
+  "End c-comment-edit.
+C comment is replaced by its edited counterpart in the appropriate C buffer.
+Indentation will be the same as the original."
+  (interactive)
+  (let ((tuple (find-c-comment-buffer)))
+    (if (null tuple)
+	(error "Not a c-comment-edit buffer."))
+    (let ((inhibit-quit t)
+	  (c-comment-c-buffer (car tuple))
+	  (c-comment-buffer (nth 1 tuple))
+	  (c-comment-start (nth 2 tuple))
+	  (c-comment-end (nth 3 tuple)))
+      (cond
+       ((buffer-modified-p)
+	;; rebuild the comment
+	(goto-char (point-min))
+	(insert "/*\n")
+	(if (string= c-comment-leader "  ")
+	    (while (not (eobp))
+	      (if (not (eolp))
+		  (insert c-comment-leader " "))
+	      (forward-line))
+	  (while (not (eobp))
+	    (insert c-comment-leader (if (eolp) "" " "))
+	    (forward-line)))
+	(if (not (char-equal (preceding-char) ?\n))
+	    (insert "\n"))
+	(insert (if (string= c-comment-leader " *") " */" "*/"))
+	;; indent if necessary
+	(let ((indention
+	       (save-excursion
+		 (set-buffer c-comment-c-buffer)
+		 (goto-char c-comment-start)
+		 (current-column))))
+	  (goto-char (point-min))
+	  (cond ((not (zerop indention))
+		 ;; first line is already indented
+		 ;; in the C buffer
+		 (forward-line)
+		 (while (not (eobp))
+		   (indent-to indention)
+		   (forward-line)))))
+	;; replace the old comment with the new
+	(save-excursion
+	  (set-buffer c-comment-c-buffer)
+	  (save-point
+	    (save-excursion
+	      (delete-region c-comment-start c-comment-end)
+	      (goto-char c-comment-start)
+	      (set-buffer c-comment-buffer)
+	      (append-to-buffer c-comment-c-buffer
+				(point-min) (point-max))))))
+       (t (message "No change.")))
+      ;; switch to the C buffer
+      (if (get-buffer-window c-comment-c-buffer)
+	  (select-window (get-buffer-window c-comment-c-buffer))
+	(switch-to-buffer c-comment-c-buffer))
+      ;; delete the window viewing the comment buffer
+      (and (get-buffer-window c-comment-buffer)
+	   (delete-window (get-buffer-window c-comment-buffer)))
+      ;; unlink the tuple from c-comment-edit-buffer-alist
+      (setq c-comment-edit-buffer-alist
+	    (delq tuple c-comment-edit-buffer-alist))
+      ;; let Emacs reclaim various resources
+      (save-excursion
+	(set-buffer c-comment-buffer)
+	(set-buffer-modified-p nil)
+	(kill-buffer c-comment-buffer))
+      (set-marker c-comment-start nil)
+      (set-marker c-comment-end nil))))
+
+(defun c-comment-edit-abort ()
+  "Abort a c-comment-edit with no change."
+  (interactive)
+  (let* ((tuple (find-c-comment-buffer))
+	 (c-comment-c-buffer (car tuple))
+	 (c-comment-buffer (nth 1 tuple))
+	 (c-comment-start (nth 2 tuple))
+	 (c-comment-end (nth 3 tuple)))
+    (if (null tuple)
+	(error "Not a c-comment-edit buffer."))
+    ;; switch to the C buffer
+    (if (get-buffer-window c-comment-c-buffer)
+	(select-window (get-buffer-window c-comment-c-buffer))
+      (switch-to-buffer c-comment-c-buffer))
+    (let ((inhibit-quit t))
+      (save-excursion
+	(set-buffer c-comment-buffer)
+	(set-buffer-modified-p nil)
+	(kill-buffer c-comment-buffer))
+      ;; unlink the tuple from c-comment-edit-buffer-alist
+      (setq c-comment-edit-buffer-alist
+	    (delq tuple c-comment-edit-buffer-alist))
+      (set-marker c-comment-start nil)
+      (set-marker c-comment-end nil)
+      (message "Aborted with no change."))))
+
+;; this loses on /* /* */ but doing it right would be grim.
+(defun within-c-comment-p ()
+  (condition-case error-data
+      (let (start end)
+	(save-point
+	  (search-backward "/*")
+	  (setq start (point))
+	  (search-forward "*/")
+	  (setq end (point)))
+	(if (< (point) end) (cons start end) nil))
+    (search-failed nil)))
+
+(defun find-c-comment-buffer (&optional buffer)
+  (or buffer (setq buffer (current-buffer)))
+  (let ((list c-comment-edit-buffer-alist))
+    (catch 'return-value
+      (while list
+	(if (eq (nth 1 (car list)) buffer)
+	    (throw 'return-value (car list))
+	  (setq list (cdr list)))))))
+	    
+(defun find-c-comment-c-buffer (&optional buffer)
+  (or buffer (setq buffer (current-buffer)))
+  (let ((list c-comment-edit-buffer-alist))
+    (catch 'return-value
+      (while list
+	(if (eq (car (car list)) buffer)
+	    (throw 'return-value (car list))
+	  (setq list (cdr list)))))))
+
+;;; c-comment.el ends here
+;;; C comment mode - An auto-filled comment mode for gnu c-mode.
+;;;
+;;; Author:  	Robert Mecklenburg
+;;;		Computer Science Dept.
+;;;          	University of Utah
+;;; From: mecklen@utah-gr.UUCP (Robert Mecklenburg)
+;;;   Also hartzell@Boulder.Colorado.EDU
+;;; (c) 1986, University of Utah
+;;;
+;;; Everyone is granted permission to copy, modify and redistribute
+;;; this file, provided the people they give it to can.
+
+;;; Synched up with: Not in FSF.
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;
+;;; I have written a "global comment" minor-mode which performs auto-fill,
+;;; fill-paragraph, and auto-indentation functions.  This function only
+;;; works for comments which occupy an entire line (not comments to the
+;;; right of code).  The mode has several options set through variables.
+;;; If the variable c-comment-starting-blank is non-nil multi-line
+;;; comments come out like this:
+;;; 
+;;; 	/*
+;;; 	 * Your favorite 
+;;; 	 * multi-line comment.
+;;; 	 */
+;;; 
+;;; otherwise they look like this:
+;;; 
+;;; 	/* Your Favorite
+;;; 	 * multi-line comment.
+;;; 	 */
+;;; 
+;;; If the variable c-comment-hanging-indent is non-nil K&R style comments
+;;; are indented automatically like this:
+;;; 
+;;; 	/* my_func - For multi-line comments with hanging indent
+;;; 	 *	     the text is lined up after the dash.
+;;; 	 */
+;;; 
+;;; otherwise the text "the text" (!) is lined up under my_func.  If a
+;;; comment fits (as typed) on a single line it remains a single line
+;;; comment even if c-comment-starting-blank is set.  If
+;;; c-comment-indenting is non-nil hitting carriage return resets the
+;;; indentation for the next line to the current line's indentation
+;;; (within the comment) like this:
+;;; 
+;;; 	/* Typing along merrily....
+;;; 	 *     Now I indent with spaces, when I hit return
+;;; 	 *     the indentation is automatically set to 
+;;; 	 *     ^ here.
+;;; 	 */
+;;; 
+;;; Due to my lack of understanding of keymaps this permanently resets M-q
+;;; to my own fill function.  I would like to have the comment mode
+;;; bindings only in comment mode but I can't seem to get that to work.
+;;; If some gnu guru can clue me in, I'd appreciate it.
+;;;
+(defvar c-comment-starting-blank t
+  "*Controls whether global comments have an initial blank line.")
+(defvar c-comment-indenting t
+  "*If set global comments are indented to the level of the previous line.")
+(defvar c-comment-hanging-indent t
+  "*If true, comments will be automatically indented to the dash.")
+(defvar c-hang-already-done t
+  "If true we have performed the haning indent already for this comment.")
+
+
+;;;
+;;; c-comment-map - This is a sparse keymap for comment mode which
+;;; 		    gets inserted when c-comment is called.
+;;; 
+(defvar c-comment-mode-map ()
+  "Keymap used in C comment mode.")
+(if c-comment-mode-map
+    ()
+  (setq c-comment-mode-map (copy-keymap c-mode-map))
+  (define-key c-comment-mode-map "\e\r" 'newline)
+  (define-key c-comment-mode-map "\eq" 'set-fill-and-fill)
+  (define-key c-comment-mode-map "\r" 'set-fill-and-return))
+ 
+;;;
+;;; c-comment - This is a filled comment mode which can format
+;;; 		indented text, do hanging indents, and symetric
+;;; 		placement of comment delimiters.
+;;; 
+(defun c-comment ()
+  "Edit a C comment with filling and indentation.
+This performs hanging indentation, symmetric placement of delimiters,
+ and Indented-Text mode style indentation.  Type 'M-x apropos
+c-comment' for information on options."
+  (interactive)
+  (let
+      ;; Save old state.
+      ((auto-fill-function (if c-comment-indenting
+			       'do-indented-auto-fill 'do-auto-fill))
+;       (comment-start nil)
+       (comment-multi-line t)
+       (comment-start-skip "/*\\*+[ 	]*")
+       (paragraph-start-ref paragraph-start)
+       fill-prefix paragraph-start paragraph-separate opoint)
+
+    ;; Determine if we are inside a comment.
+    (setq in-comment
+	  (save-excursion
+	    (and (re-search-backward "/\\*\\|\\*/" 0 t)
+		 (string= "/*" (buffer-substring (point) (+ (point) 2))))))
+
+    ;; Indent the comment and set the fill prefix to comment continuation
+    ;; string.  If we are already in a comment get the indentation on
+    ;; the current line.
+    (setq c-hang-already-done nil)
+
+    ;; Set the beginning of the comment and insert the blank line if needed.
+    (use-local-map c-comment-mode-map)
+    (if (not in-comment)
+	(progn (c-indent-line)
+	       (insert "/* ")
+	       (setq fill-prefix (get-current-fill (point)))
+	       (recursive-edit)
+
+	       ;; If the comment fits on one line, place the close
+	       ;; comment at the end of the line.  Otherwise, newline.
+	       (setq opoint (point))
+	       (if (and (save-excursion (beginning-of-line)
+					(search-forward "/*" opoint t))
+			(<= (+ (current-column) 3) 79))
+		   (insert " */")
+		 (insert "\n*/"))
+
+	       (c-indent-line))
+      (progn (setq fill-prefix (get-current-fill (point)))
+	     (recursive-edit)
+	     (search-forward "*/" (buffer-size) t)
+	     (forward-line 1)))
+
+    ;; If starting blank enabled, insert a newline, etc., but only if
+    ;; this comment requires multiple lines.
+    (if c-comment-starting-blank
+	(save-excursion
+	  (setq opoint (point))
+	  (forward-line -1)
+	  (if (or (null (search-forward "/*" opoint t))
+		  (null (search-forward "*/" opoint t)))
+	      (progn
+		(search-backward "/*")
+		(re-search-forward comment-start-skip opoint t)
+		(setq fill-prefix (get-current-fill (point)))
+		(if (not (looking-at "\n"))
+		    (insert ?\n fill-prefix))))))
+;		    (indent-new-comment-line))))))
+
+    ;; Move cursor to indentation.
+    (c-indent-line)
+    (use-local-map c-mode-map)
+    )
+  )
+
+
+;;;
+;;; set-fill-and-fill - Get the current fill for this line and fill
+;;; 			the paragraph.
+;;; 
+(defun set-fill-and-fill (arg)
+  "Get the fill-prefix and fill the current paragraph."
+
+  (interactive "P")
+  (setq fill-prefix (get-current-fill (point)))
+  (fill-paragraph arg))
+
+;;;
+;;; set-fill-and-return - Set the current fill prefix and
+;;; 			  indent-new-comment-line.
+;;; 
+(defun set-fill-and-return ()
+  "Set the current fill prefix and move to the next line."
+
+  (interactive)
+  (if c-comment-indenting
+      (setq fill-prefix (get-current-fill (point))))
+  (insert ?\n fill-prefix))
+
+;;;
+;;; do-indented-auto-fill - Perform the auto-fill function, but get
+;;; 			    the fill-prefix first.
+;;; 
+(defun do-indented-auto-fill ()
+  "Perform auto-fill, but get fill-prefix first."
+
+  (let ((opoint (point)))
+    (save-excursion
+      (move-to-column (1+ fill-column))
+      (skip-chars-backward "^ \t\n")
+      (if (bolp)
+	  (re-search-forward "[ \t]" opoint t))
+      ;; If there is a space on the line before fill-point,
+      ;; and nonspaces precede it, break the line there.
+      (if (save-excursion
+	    (skip-chars-backward " \t")
+	    (not (bolp)))
+
+	  ;; If we are wrapping to a new line, figure out the indentation on
+	  ;; the current line first.
+	  (progn
+	    (setq fill-prefix (get-current-fill opoint))
+	    (insert ?\n fill-prefix)))))
+;	    (indent-new-comment-line)))))
+  )
+
+
+;;;
+;;; get-current-fill - Get the fill-prefix for the current line.  This
+;;; 		       assumes that the valid fill prefix is between
+;;; 		       (beginning-of-line) and (point).
+;;; 
+(defun get-current-fill (pnt)
+  "Get the current fill prefix.
+A valid fill prefix must be between the beginning of the line and point."
+
+  (let ((opoint pnt) fill last-char)
+    (save-excursion
+      (beginning-of-line)
+      (setq fill
+	    (buffer-substring (point)
+			      (progn
+				(re-search-forward comment-start-skip opoint t)
+				(point))))
+
+      ;; Be sure there is trailing white space.
+      (setq last-char (substring fill (1- (length fill)) (length fill)))
+      (if (and (not (string= " " last-char))
+	       (not (string= "	" last-char)))
+	  (setq fill (concat fill " ")))
+
+      (setq fill (replace-letter fill "/" " "))
+
+      ;; Get the hanging indentation if we haven't already.
+      (if (and c-comment-hanging-indent (not c-hang-already-done))
+	  (let ((curr (point))
+		(opnt (progn (end-of-line) (point))))
+	    (beginning-of-line)
+	    (if (search-forward " - " opnt t)
+		(progn
+		  (setq fill (concat fill (make-string (- (point) curr) 32)))
+		  (setq c-hang-already-done t)))))
+
+      ;; Set the paragraph delimiters.
+      (setq paragraph-start (concat paragraph-start-ref
+				    "\\|^"
+				    (regexp-quote
+				     (substring fill
+						0 (1- (length fill))))
+				    "$"))
+      (setq paragraph-separate paragraph-start))
+    fill)
+  )
+  
+
+;;;
+;;; replace-letter - Given a string, an old letter and a new letter,
+;;; 		     perform the substitution.
+;;; 
+(defun replace-letter (str old-letter new-letter)
+  (let (new-str c
+	(sp 0)
+	(size (length str)))
+    (while (< sp size)
+      (setq c (substring str sp (1+ sp)))
+      (setq new-str (concat new-str (if (string= c old-letter) new-letter c)))
+      (setq sp (1+ sp)))
+    new-str))
+;; c-style.el --- sets c-style control variables.
+;; Copyright (C) 1992-1993 Free Software Foundation, Inc.
+
+;; This file is part of XEmacs.
+
+;; XEmacs 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.
+
+;; XEmacs 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 XEmacs; see the file COPYING.  If not, write to the 
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+;;
+;; LCD Archive Entry:
+;; c-style|Daniel LaLiberte|liberte@cs.uiuc.edu
+;; |sets c-style control variables
+;; |Thu Feb 27 13:42:57 CST 1992|Version: 2.1|~/as-is/c-src-doc.el.Z
+;;
+;;; Synched up with: Not in FSF.
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;
+;;; There are several ways to call set-c-style described below.
+;;; None of these methods reindent your program - they only affect
+;;; new indentation.
+;;;
+;;; - Just call set-c-style in your c-mode-hook.
+;;;    Without style argument, default-c-style will be used.
+;;;    With style argument, this will set the style for every 
+;;;    c-mode buffer the same.
+;;;
+;;; - Call set-c-style from the Local Variables list.
+;;;    e.g. "eval:(set-c-style 'C++)"
+;;;
+;;; - Call set-c-style interactively.  It prompts for the style name
+;;;    with completion using default-c-style.
+;;;
+;;; For convenience, put one of the following in your .emacs:
+;;;    (autoload 'set-c-style "c-style" nil t)
+;;; or (load "c-style")
+;;; =====================================================
+
+(defvar default-c-style 'GNU
+  "*The default value of c-style.  Set this in your .emacs.")
+
+;; The following predefined styles are all I know about.
+;; If you learn of another style that has a "big" following, please
+;; send me the parameters.
+
+(defvar c-style-alist 
+  '((GNU 
+     (c-indent-level 2)
+     (c-continued-statement-offset 2)
+     (c-brace-offset 0)
+     (c-argdecl-indent 5)
+     (c-label-offset -2))
+
+    (BSD
+     (c-indent-level 8)
+     (c-continued-statement-offset 8)
+     (c-brace-offset -8)
+     (c-argdecl-indent 8)
+     (c-label-offset -8))
+
+    (K&R 
+     (c-indent-level 5)
+     (c-continued-statement-offset 5)
+     (c-brace-offset -5)
+     (c-argdecl-indent 0)
+     (c-label-offset -5))
+
+    (BS   ; was C++ 
+     (c-indent-level 4)
+     (c-continued-statement-offset 4)
+     (c-brace-offset -4)
+     (c-argdecl-indent 4)
+     (c-label-offset -4))
+
+    ;; From Lynn Slater
+    (LRS
+     (c-indent-level 4)
+     (c-continued-statement-offset 4)
+     (c-brace-offset 0)
+     (c-argdecl-indent 4)
+     (c-label-offset -2)
+     (c-auto-newline nil))
+
+    (Plauger
+     (c-indent-level 0)
+     (c-continued-statement-offset 8)
+     (c-continued-brace-offset -8)
+     (c-brace-offset 8)
+     (c-brace-imaginary-offset 0)
+     (c-argdecl-indent 0)
+     (c-label-offset -8)
+     (c-auto-newline t)
+     (c-tab-always-indent t))
+
+    ;; From Jozsef A Toth <jtoth+@pitt.edu>
+    ;; Is this really the Whitesmith style?
+    (Alman				
+     (c-argdecl-indent 0)
+     (c-brace-imaginary-offset 2)  ;;; ????
+     (c-brace-offset 0)
+     (c-continued-statement-offset 2)
+     (c-indent-level 0)
+     (c-label-offset -2)
+     (c-auto-newline t)
+     (comment-column 40)
+     (tab-width 2)
+     (fill-column '79))
+
+    (Gould
+     (c-indent-level 4)
+     (c-continued-statement-offset 4)
+     (c-brace-offset -4)
+     (c-argdecl-indent 8)
+     (c-label-offset -2)
+     (c-brace-imaginary-offset 0))
+     
+    ;; From Joan Eslinger <wombat@kilimanjaro.key.amdahl.com>
+    (WRS 
+     (c-indent-level 0)
+     (c-continued-statement-offset 4)
+     (c-brace-offset 0)
+     (c-argdecl-indent 4)
+     (c-label-offset -2)
+     (c-brace-imaginary-offset 4)
+     (c-continued-brace-offset -4))
+    ))
+  
+(defvar c-style nil
+  "The buffer local c-mode indentation style.")
+
+;; Add style name to mode line.  Assumes minor-mode-alist is not buffer local.
+;; Thanks to Joan Eslinger.
+
+(defvar c-style-name nil
+  "The style name for a c-mode indentation style.
+This is to be set by set-c-style, and used by the mode line.")
+
+(or (assq 'c-style-name minor-mode-alist)
+    (setq minor-mode-alist
+	  (purecopy
+	   (append minor-mode-alist
+		   ;; use undocumented feature
+		   '((c-style-name c-style-name))))))
+
+(defun set-c-style (&optional style)
+  "Set up the c-mode style variables from STYLE if it is given, or
+default-c-style otherwise.  It makes the c indentation style variables
+buffer local."
+
+  (interactive)
+
+  (let ((c-styles (mapcar 'car c-style-alist))) ; for completion
+    (if (interactive-p)
+	(setq style
+	      (let ((style-string	; Get style name with completion.
+		     (completing-read
+		      (format "Set c-mode indentation style to (default %s): "
+			      default-c-style)
+		      (vconcat c-styles)
+		      (function (lambda (arg) (memq arg c-styles)))
+		      )))
+		(if (string-equal "" style-string)
+		    default-c-style
+		  (intern style-string))
+		)))
+    
+    ;; If style is nil, use default-c-style.
+    (setq style (or style default-c-style))
+    
+    (make-local-variable 'c-style)
+    (if (memq style c-styles)
+	(setq c-style style)
+      (error "Undefined c style: %s" style)
+      )
+    (message "c-style: %s" c-style)
+    
+    ;; Set the c-style-name
+    (make-local-variable 'c-style-name)
+    (setq c-style-name (format " %s" c-style))
+
+    ;; Finally, set the indentation style variables making each one local.
+    (mapcar (function (lambda (c-style-pair)
+			(make-local-variable (car c-style-pair))
+			(set (car c-style-pair)
+			     (car (cdr c-style-pair)))))
+	    (cdr (assq c-style c-style-alist)))
+    c-style
+    ))
+;;; cmacexp.el --- expand C macros in a region
+
+;; Copyright (C) 1992, 1994, 1996 Free Software Foundation, Inc.
+
+;; Author: Francesco Potorti` <pot@cnuce.cnr.it>
+;; Version: $Id$
+;; Adapted-By: ESR
+;; Keywords: c
+
+;; This file is part of XEmacs.
+
+;; XEmacs 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.
+
+;; XEmacs 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 XEmacs; see the file COPYING.  If not, write to the Free
+;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+;; 02111-1307, USA.
+
+;;; Synched up with: FSF 19.34.
+
+;; USAGE =============================================================
+
+;; In C mode C-C C-e is bound to c-macro-expand.  The result of the
+;; expansion is put in a separate buffer.  A user option allows the
+;; window displaying the buffer to be optimally sized.
+;;
+;; When called with a C-u prefix, c-macro-expand replaces the selected
+;; region with the expansion.  Both the preprocessor name and the
+;; initial flag can be set by the user.  If c-macro-prompt-flag is set
+;; to a non-nil value the user is offered to change the options to the
+;; preprocessor each time c-macro-expand is invoked.  Preprocessor
+;; arguments default to the last ones entered.  If c-macro-prompt-flag
+;; is nil, one must use M-x set-variable to set a different value for
+;; c-macro-cppflags.
+
+;; A c-macro-expansion function is provided for non-interactive use.
+
+;; INSTALLATION ======================================================
+
+;; Put the following in your ~/.emacs file.
+
+;; If you want the *Macroexpansion* window to be not higher than
+;; necessary: 
+;;(setq c-macro-shrink-window-flag t)
+;;
+;; If you use a preprocessor other than /lib/cpp (be careful to set a
+;; -C option or equivalent in order to make the preprocessor not to
+;; strip the comments):
+;;(setq c-macro-preprocessor "gpp -C")
+;;
+;; If you often use a particular set of flags:
+;;(setq c-macro-cppflags "-I /usr/include/local -DDEBUG"
+;;
+;; If you want the "Preprocessor arguments: " prompt:
+;;(setq c-macro-prompt-flag t)
+
+;; BUG REPORTS =======================================================
+
+;; Please report bugs, suggestions, complaints and so on to
+;; pot@cnuce.cnr.it (Francesco Potorti`).
+
+;; IMPROVEMENTS OVER emacs 18.xx cmacexp.el ==========================
+
+;; - A lot of user and programmer visible changes.  See above.
+;; - #line directives are inserted, so __LINE__ and __FILE__ are
+;;   correctly expanded.  Works even with START inside a string, a
+;;   comment or a region #ifdef'd away by cpp. cpp is invoked with -C,
+;;   making comments visible in the expansion.
+;; - All work is done in core memory, no need for temporary files.
+
+;; ACKNOWLEDGEMENTS ==================================================
+
+;; A lot of thanks to Don Maszle who did a great work of testing, bug
+;; reporting and suggestion of new features.  This work has been
+;; partially inspired by Don Maszle and Jonathan Segal's.
+
+;; BUGS ==============================================================
+
+;; If the start point of the region is inside a macro definition the
+;; macro expansion is often inaccurate.
+
+
+(require 'cc-mode)
+
+(provide 'cmacexp)
+
+(defgroup c-macro nil
+  "Expand C macros in a region."
+  :group 'c)
+
+
+(defcustom c-macro-shrink-window-flag nil
+  "*Non-nil means shrink the *Macroexpansion* window to fit its contents."
+  :type 'boolean
+  :group 'c-macro)
+
+(defcustom c-macro-prompt-flag nil
+  "*Non-nil makes `c-macro-expand' prompt for preprocessor arguments."
+  :type 'boolean
+  :group 'c-macro)
+
+(defcustom c-macro-preprocessor
+  ;; Cannot rely on standard directory on MS-DOS to find CPP.
+  (cond ((eq system-type 'ms-dos) "cpp -C")
+	;; Solaris has it in an unusual place.
+	((and (string-match "^[^-]*-[^-]*-\\(solaris\\|sunos5\\)"
+			    system-configuration)
+	      (file-exists-p "/opt/SUNWspro/SC3.0.1/bin/acomp"))
+	 "/opt/SUNWspro/SC3.0.1/bin/acomp -C -E")
+	(t "/lib/cpp -C"))
+  "The preprocessor used by the cmacexp package.
+
+If you change this, be sure to preserve the `-C' (don't strip comments)
+option, or to set an equivalent one."
+  :type 'string
+  :group 'c-macro)
+
+(defcustom c-macro-cppflags ""
+  "*Preprocessor flags used by `c-macro-expand'."
+  :type 'string
+  :group 'c-macro)
+
+(defconst c-macro-buffer-name "*Macroexpansion*")
+
+;; Autoload for XEmacs
+;;;###autoload
+(defun c-macro-expand (start end subst)
+  "Expand C macros in the region, using the C preprocessor.
+Normally display output in temp buffer, but
+prefix arg means replace the region with it.
+
+`c-macro-preprocessor' specifies the preprocessor to use.
+Prompt for arguments to the preprocessor \(e.g. `-DDEBUG -I ./include')
+if the user option `c-macro-prompt-flag' is non-nil.
+
+Noninteractive args are START, END, SUBST.
+For use inside Lisp programs, see also `c-macro-expansion'."
+
+  (interactive "r\nP")
+  (let ((inbuf (current-buffer))
+	(displaybuf (if subst
+			(get-buffer c-macro-buffer-name)
+		      (get-buffer-create c-macro-buffer-name)))
+	(expansion ""))
+    ;; Build the command string.
+    (if c-macro-prompt-flag
+	(setq c-macro-cppflags
+	      (read-string "Preprocessor arguments: "
+			   c-macro-cppflags)))
+    ;; Decide where to display output.
+    (if (and subst
+	     (and buffer-read-only (not inhibit-read-only))
+	     (not (eq inbuf displaybuf)))
+	(progn
+	  (message
+	   "Buffer is read only: displaying expansion in alternate window")
+	  (sit-for 2)
+	  (setq subst nil)
+	  (or displaybuf
+	      (setq displaybuf (get-buffer-create c-macro-buffer-name)))))
+    ;; Expand the macro and output it.
+    (setq expansion (c-macro-expansion start end
+				       (concat c-macro-preprocessor " "
+					       c-macro-cppflags) t))
+    (if subst
+	(let ((exchange (= (point) start)))
+	  (delete-region start end)
+	  (insert expansion)
+	  (if exchange
+	      (exchange-point-and-mark)))
+      (set-buffer displaybuf)
+      (setq buffer-read-only nil)
+      (buffer-disable-undo displaybuf)
+      (erase-buffer)
+      (insert expansion)
+      (set-buffer-modified-p nil)
+      (if (string= "" expansion)
+	  (message "Null expansion")
+	(c-macro-display-buffer))
+      (setq buffer-read-only t)
+      (setq buffer-auto-save-file-name nil)
+      (bury-buffer displaybuf))))
+
+
+;; Display the current buffer in a window which is either just large
+;; enough to contain the entire buffer, or half the size of the
+;; screen, whichever is smaller.  Do not select the new
+;; window.
+;;
+;; Several factors influence window resizing so that the window is
+;; sized optimally if it is created anew, and so that it is messed
+;; with minimally if it has been created by the user.  If the window
+;; chosen for display exists already but contains something else, the
+;; window is not re-sized.  If the window already contains the current
+;; buffer, it is never shrunk, but possibly expanded.  Finally, if the
+;; variable c-macro-shrink-window-flag is nil the window size is *never*
+;; changed.
+(defun c-macro-display-buffer ()
+  (goto-char (point-min))
+  (c-mode)
+  (let ((oldwinheight (window-height))
+	(alreadythere			;the window was already there
+	 (get-buffer-window (current-buffer)))
+	(popped nil))			;the window popped changing the layout 
+    (or alreadythere
+	(progn
+	  (display-buffer (current-buffer) t)
+	  (setq popped (/= oldwinheight (window-height)))))
+    (if (and c-macro-shrink-window-flag	;user wants fancy shrinking :\)
+	     (or alreadythere popped))
+	;; Enlarge up to half screen, or shrink properly.
+	(let ((oldwin (selected-window))
+	      (minheight 0)
+	      (maxheight 0))
+	  (save-excursion
+	    (select-window (get-buffer-window (current-buffer)))
+	    (setq minheight (if alreadythere
+				(window-height)
+			      window-min-height))
+	    ;; XEmacs change
+	    (setq maxheight (/ (screen-height) 2))
+	    (enlarge-window (- (min maxheight
+				    (max minheight
+					 (+ 2 (vertical-motion (point-max)))))
+			       (window-height)))
+	    (goto-char (point-min))
+	    (select-window oldwin))))))
+
+
+(defun c-macro-expansion (start end cppcommand &optional display)
+  "Run a preprocessor on region and return the output as a string.
+Expand the region between START and END in the current buffer using
+the shell command CPPCOMMAND (e.g. \"/lib/cpp -C -DDEBUG\").
+Be sure to use a -C (don't strip comments) or equivalent option.
+Optional arg DISPLAY non-nil means show messages in the echo area."
+
+;; Copy the current buffer's contents to a temporary hidden buffer.
+;; Delete from END to end of buffer.  Insert a preprocessor #line
+;; directive at START and after each #endif following START that are
+;; not inside a comment or a string.  Put all the strings thus
+;; inserted (without the "line" substring) in a list named linelist.
+;; If START is inside a comment, prepend "*/" and append "/*" to the
+;; #line directive.  If inside a string, prepend and append "\"".
+;; Preprocess the buffer contents, then look for all the lines stored
+;; in linelist starting from end of buffer.  The last line so found is
+;; where START was, so return the substring from point to end of
+;; buffer. 
+  (let ((inbuf (current-buffer))
+	(outbuf (get-buffer-create " *C Macro Expansion*"))
+	(filename (if (and buffer-file-name
+			   (string-match (regexp-quote default-directory)
+					 buffer-file-name))
+		      (substring buffer-file-name (match-end 0))
+		    (buffer-name)))
+	(mymsg (format "Invoking %s%s%s on region..."
+		       c-macro-preprocessor
+		       (if (string= "" c-macro-cppflags) "" " ")
+		       c-macro-cppflags))
+	(uniquestring "??? !!! ??? start of c-macro expansion ??? !!! ???")
+	(startlinenum 0)
+	(linenum 0)
+	(startstat ())
+	(startmarker "")
+	(exit-status 0)
+	(tempname (make-temp-name (concat
+				   (or (getenv "TMPDIR") (getenv "TEMP")
+				       (getenv "TMP") "/tmp")
+				   "/"))))
+    (unwind-protect
+	(save-excursion
+	  (save-restriction
+	    (widen)
+            (let ((in-syntax-table (syntax-table)))
+              (set-buffer outbuf)
+              (setq buffer-read-only nil)
+              (erase-buffer)
+              (set-syntax-table in-syntax-table))
+	    (insert-buffer-substring inbuf 1 end))
+
+	  ;; We have copied inbuf to outbuf.  Point is at end of
+	  ;; outbuf.  Inset a newline at the end, so cpp can correctly
+	  ;; parse a token ending at END.
+          (insert "\n")
+
+	  ;; Save sexp status and line number at START.
+	  (setq startstat (parse-partial-sexp 1 start))
+	  (setq startlinenum (+ (count-lines 1 (point))
+				(if (bolp) 1 0)))
+
+	  ;; Now we insert the #line directives after all #endif or
+	  ;; #else following START going backward, so the lines we
+	  ;; insert don't change the line numbers.
+	  ;(switch-to-buffer outbuf) (debug)	;debugging instructions
+	  (goto-char (point-max))
+	  (while (re-search-backward "\n#\\(endif\\|else\\)\\>" start 'move)
+	    (if (equal (nthcdr 3 (parse-partial-sexp start (point)
+						     nil nil startstat))
+		       '(nil nil nil 0 nil)) ;neither in string nor in
+					     ;comment nor after quote
+		(progn
+		  (goto-char (match-end 0))
+		  (setq linenum (+ startlinenum
+				   (count-lines start (point))))
+		  (insert (format "\n#line %d \"%s\"\n" linenum filename))
+		  (goto-char (match-beginning 0)))))
+
+	  ;; Now we are at START.  Insert the first #line directive.
+	  ;; This must work even inside a string or comment, or after a
+	  ;; quote.
+	  (let* ((startinstring (nth 3 startstat))
+		 (startincomment (nth 4 startstat))
+		 (startafterquote (nth 5 startstat))
+		 (startinbcomment (nth 7 startstat)))
+	    (insert (if startafterquote " " "")
+		    (cond (startinstring
+			   (char-to-string startinstring))
+			  (startincomment "*/")
+			  (""))
+		    (setq startmarker
+			  (concat "\n" uniquestring
+				  (cond (startinstring
+					 (char-to-string startinstring))
+					(startincomment "/*")
+					(startinbcomment "//"))
+				  (if startafterquote "\\")))
+		    (format "\n#line %d \"%s\"\n" startlinenum filename)))
+
+	  ;; Call the preprocessor.
+	  (if display (message mymsg))
+	  (setq exit-status
+		(call-process-region 1 (point-max)
+				     shell-file-name
+				     t (list t tempname) nil "-c"
+				     cppcommand))
+	  (if display (message (concat mymsg "done")))
+	  (if (= (buffer-size) 0)
+	      ;; Empty output is normal after a fatal error.
+	      (insert "\nPreprocessor produced no output\n")
+	    ;; Find and delete the mark of the start of the expansion.
+	    ;; Look for `# nn "file.c"' lines and delete them.
+	    (goto-char (point-min))
+	    (search-forward startmarker)
+	    (delete-region 1 (point)))
+	  (while (re-search-forward (concat "^# [0-9]+ \""
+					    (regexp-quote filename)
+					    "\"") nil t)
+	    (beginning-of-line)
+	    (let ((beg (point)))
+	      (forward-line 1)
+	      (delete-region beg (point))))
+
+	  ;; If CPP got errors, show them at the beginning.
+	  ;; MS-DOS shells don't return the exit code of their children.
+	  ;; Look at the size of the error message file instead, but
+	  ;; don't punish those MS-DOS users who have a shell that does
+	  ;; return an error code.
+	  (or (and (or (not (boundp 'msdos-shells))
+		       (not (member (file-name-nondirectory shell-file-name)
+				    msdos-shells)))
+		   (eq exit-status 0))
+	      (zerop (nth 7 (file-attributes (expand-file-name tempname))))
+	      (progn
+		(goto-char (point-min))
+		;; Put the messages inside a comment, so they won't get in
+		;; the way of font-lock, highlighting etc.
+		(insert
+		 (format "/* Preprocessor terminated with status %s\n\n   Messages from `%s\':\n\n"
+			 exit-status cppcommand))
+		(goto-char (+ (point)
+			      (nth 1 (insert-file-contents tempname))))
+		(insert "\n\n*/\n")))
+	  (delete-file tempname)
+
+	  ;; Compute the return value, keeping in account the space
+	  ;; inserted at the end of the buffer.
+	  (buffer-substring 1 (max 1 (- (point-max) 1))))
+
+      ;; Cleanup.
+      (kill-buffer outbuf))))
+
+;;; cmacexp.el ends here
+;;; hide-ifdef-mode.el --- hides selected code within ifdef.
+
+;; Copyright (C) 1988, 1994 Free Software Foundation, Inc.
+
+;; Author: Dan LaLiberte <liberte@a.cs.uiuc.edu>
+;; Maintainer: FSF
+;; Keywords: c, outlines
+
+;; This file is part of XEmacs.
+
+;; XEmacs 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.
+
+;; XEmacs 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 XEmacs; see the file COPYING.  If not, write to the Free
+;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+;; 02111-1307, USA.
+
+;;; Synched up with: FSF 19.34.
+
+;;; Commentary:
+
+;; To initialize, toggle the hide-ifdef minor mode with
+;;
+;; M-x hide-ifdef-mode
+;;
+;; This will set up key bindings and call hide-ifdef-mode-hook if it
+;; has a value.  To explicitly hide ifdefs using a buffer-local
+;; define list (default empty), type
+;;
+;; M-x hide-ifdefs  or C-c @ h
+;;
+;; Hide-ifdef suppresses the display of code that the preprocessor wouldn't
+;; pass through.  The support of constant expressions in #if lines is 
+;; limited to identifiers, parens, and the operators: &&, ||, !, and
+;; "defined".  Please extend this.
+;;
+;; The hidden code is marked by ellipses (...).  Be
+;; cautious when editing near ellipses, since the hidden text is
+;; still in the buffer, and you can move the point into it and modify
+;; text unawares.  If you don't want to see the ellipses, set 
+;; selective-display-ellipses to nil.  But this can be dangerous.
+;; You can make your buffer read-only while hide-ifdef-hiding by setting
+;; hide-ifdef-read-only to a non-nil value.  You can toggle this 
+;; variable with hide-ifdef-toggle-read-only (C-c @ C-q).
+;;
+;; You can undo the effect of hide-ifdefs by typing
+;;
+;; M-x show-ifdefs  or C-c @ s
+;;
+;; Use M-x hide-ifdef-define (C-c @ d) to define a symbol.
+;; Use M-x hide-ifdef-undef (C-c @ u) to undefine a symbol.
+;;
+;; If you define or undefine a symbol while hide-ifdef-mode is in effect,
+;; the display will be updated.  Only the define list for the current
+;; buffer will be affected.  You can save changes to the local define
+;; list with hide-ifdef-set-define-alist.  This adds entries 
+;; to hide-ifdef-define-alist.
+;;
+;; If you have defined a hide-ifdef-mode-hook, you can set
+;; up a list of symbols that may be used by hide-ifdefs as in the
+;; following example:
+;;
+;; (setq hide-ifdef-mode-hook
+;;      '(lambda ()
+;;	 (if (not hide-ifdef-define-alist)
+;;	     (setq hide-ifdef-define-alist
+;;		  '((list1 ONE TWO)
+;;		    (list2 TWO THREE)
+;;		    )))
+;;	 (hide-ifdef-use-define-alist 'list2) ; use list2 by default
+;;	 ))
+;;
+;; You can call hide-ifdef-use-define-alist (C-c u) at any time to specify
+;; another list to use.
+;;
+;; To cause ifdefs to be hidden as soon as hide-ifdef-mode is called,
+;; set hide-ifdef-initially to non-nil.
+;;
+;; If you set hide-ifdef-lines to t, hide-ifdefs hides all the #ifdef lines.
+;; In the absence of highlighting, that might be a bad idea.  If you set
+;; hide-ifdef-lines to nil (the default), the surrounding preprocessor
+;; lines will be displayed.  That can be confusing in its own
+;; right.  Other variations on display are possible, but not much
+;; better.
+;;
+;; You can explicitly hide or show individual ifdef blocks irrespective
+;; of the define list by using hide-ifdef-block and show-ifdef-block.
+;;
+;; You can move the point between ifdefs with forward-ifdef, backward-ifdef,
+;; up-ifdef, down-ifdef, next-ifdef, and previous-ifdef.
+;;
+;; If you have minor-mode-alist in your mode line (the default) two labels
+;; may appear.  "Ifdef" will appear when hide-ifdef-mode is active.  "Hiding"
+;; will appear when text may be hidden ("hide-ifdef-hiding" is non-nil).
+;;
+;; Written by Brian Marick, at Gould, Computer Systems Division, Urbana IL.
+;; Extensively modified by Daniel LaLiberte (while at Gould).
+;;
+;; You may freely modify and distribute this, but keep a record
+;; of modifications and send comments to:
+;; 	 liberte@a.cs.uiuc.edu  or  ihnp4!uiucdcs!liberte
+;; I will continue to upgrade hide-ifdef-mode
+;; with your contributions.
+
+;;; Code:
+
+(require 'cc-mode)
+
+(defvar hide-ifdef-mode-submap nil
+  "Keymap used with Hide-Ifdef mode.")
+
+(defvar hide-ifdef-mode-map nil
+  "Keymap used with Hide-Ifdef mode.")
+
+(defconst hide-ifdef-mode-prefix-key "\C-c@"
+  "Prefix key for all Hide-Ifdef mode commands.")
+
+;; Set up the submap that goes after the prefix key.
+(if hide-ifdef-mode-submap
+    ()				; Don't redefine it.
+  (setq hide-ifdef-mode-submap (make-sparse-keymap))
+  (define-key hide-ifdef-mode-submap "d" 'hide-ifdef-define)
+  (define-key hide-ifdef-mode-submap "u" 'hide-ifdef-undef)
+  (define-key hide-ifdef-mode-submap "D" 'hide-ifdef-set-define-alist)
+  (define-key hide-ifdef-mode-submap "U" 'hide-ifdef-use-define-alist)
+
+  (define-key hide-ifdef-mode-submap "h" 'hide-ifdefs)
+  (define-key hide-ifdef-mode-submap "s" 'show-ifdefs)
+  (define-key hide-ifdef-mode-submap "\C-d" 'hide-ifdef-block)
+  (define-key hide-ifdef-mode-submap "\C-s" 'show-ifdef-block)
+
+  (define-key hide-ifdef-mode-submap "\C-q" 'hide-ifdef-toggle-read-only)
+  (let ((where (where-is-internal 'toggle-read-only nil t)))
+    (if where
+	(define-key hide-ifdef-mode-submap
+	  where
+	  'hide-ifdef-toggle-outside-read-only)))
+  )
+
+;; Set up the mode's main map, which leads via the prefix key to the submap.
+(if hide-ifdef-mode-map
+    ()
+  (setq hide-ifdef-mode-map (make-sparse-keymap))
+  (define-key hide-ifdef-mode-map hide-ifdef-mode-prefix-key
+    hide-ifdef-mode-submap))
+
+(defvar hide-ifdef-mode nil
+  "Non-nil when hide-ifdef-mode is activated.")
+
+(defvar hide-ifdef-hiding nil
+  "Non-nil when text may be hidden.")
+
+(or (assq 'hide-ifdef-hiding minor-mode-alist)
+    (setq minor-mode-alist
+          (cons '(hide-ifdef-hiding " Hiding")
+                minor-mode-alist)))
+
+;(or (assq 'hide-ifdef-mode minor-mode-alist)
+;    (setq minor-mode-alist
+;          (cons '(hide-ifdef-mode " Ifdef")
+;                minor-mode-alist)))
+;; XEmacs: do it right.
+;;;###autoload
+(add-minor-mode 'hide-ifdef-mode " Ifdef" 'hide-ifdef-mode-map)
+
+;; fix c-mode syntax table so we can recognize whole symbols.
+(defvar hide-ifdef-syntax-table
+  (copy-syntax-table c-mode-syntax-table)
+  "Syntax table used for tokenizing #if expressions.")
+
+(modify-syntax-entry ?_ "w" hide-ifdef-syntax-table)
+(modify-syntax-entry ?& "." hide-ifdef-syntax-table)
+(modify-syntax-entry ?\| "." hide-ifdef-syntax-table)
+
+;;;###autoload
+(defun hide-ifdef-mode (arg)
+  "Toggle Hide-Ifdef mode.  This is a minor mode, albeit a large one.
+With ARG, turn Hide-Ifdef mode on if arg is positive, off otherwise.
+In Hide-Ifdef mode, code within #ifdef constructs that the C preprocessor
+would eliminate may be hidden from view.  Several variables affect
+how the hiding is done:
+
+hide-ifdef-env
+	An association list of defined and undefined symbols for the
+	current buffer.  Initially, the global value of `hide-ifdef-env'
+	is used.
+
+hide-ifdef-define-alist
+	An association list of defined symbol lists.  
+        Use `hide-ifdef-set-define-alist' to save the current `hide-ifdef-env'
+        and `hide-ifdef-use-define-alist' to set the current `hide-ifdef-env'
+        from one of the lists in `hide-ifdef-define-alist'.
+
+hide-ifdef-lines
+	Set to non-nil to not show #if, #ifdef, #ifndef, #else, and
+	#endif lines when hiding.
+
+hide-ifdef-initially
+	Indicates whether `hide-ifdefs' should be called when Hide-Ifdef mode
+	is activated.
+
+hide-ifdef-read-only
+	Set to non-nil if you want to make buffers read only while hiding.
+	After `show-ifdefs', read-only status is restored to previous value.
+
+\\{hide-ifdef-mode-map}"
+
+  (interactive "P")
+  (make-local-variable 'hide-ifdef-mode)
+  (setq hide-ifdef-mode
+	(if (null arg)
+	    (not hide-ifdef-mode)
+	  (> (prefix-numeric-value arg) 0)))
+  
+  ;; XEmacs change
+  (redraw-modeline)
+
+  (if hide-ifdef-mode
+      (progn
+	; fix c-mode syntax table so we can recognize whole symbols.
+	;; XEmacs:  Maybe we don't need this any more with cc-mode? -sb
+	;; (modify-syntax-entry ?_ "w")
+	;; (modify-syntax-entry ?& ".")
+	;; (modify-syntax-entry ?\| ".")
+
+	; inherit global values
+	(make-local-variable 'hide-ifdef-env)
+	(setq hide-ifdef-env (default-value 'hide-ifdef-env))
+
+	(make-local-variable 'hide-ifdef-hiding)
+	(setq hide-ifdef-hiding (default-value 'hide-ifdef-hiding))
+
+	(make-local-variable 'hif-outside-read-only)
+	(setq hif-outside-read-only buffer-read-only)
+
+	(run-hooks 'hide-ifdef-mode-hook)
+
+	(if hide-ifdef-initially
+	    (hide-ifdefs)
+	  (show-ifdefs))
+	(message "Enter Hide-Ifdef mode")
+	)
+     ; else end hide-ifdef-mode
+    (if hide-ifdef-hiding
+	(show-ifdefs))
+    (message "Exit Hide-Ifdef mode")
+    ))
+  
+
+;; from outline.el with docstring fixed.
+(defun hif-outline-flag-region (from to flag)
+  "Hides or shows lines from FROM to TO, according to FLAG.
+If FLAG is \\n (newline character) then text is shown, while if FLAG is \\^M
+\(control-M) the text is hidden."
+  (let ((modp (buffer-modified-p)))
+    (unwind-protect (progn
+		      (subst-char-in-region from to
+			      (if (= flag ?\n) ?\^M ?\n)
+			      flag t) )
+      (set-buffer-modified-p modp))
+    ))
+
+(defun hif-show-all ()
+  "Show all of the text in the current buffer."
+  (interactive)
+  (hif-outline-flag-region (point-min) (point-max) ?\n))
+
+;; By putting this on after-revert-hook, we arrange that it only
+;; does anything when revert-buffer avoids turning off the mode.
+;; (That can happen in VC.)
+(defun hif-before-revert-function ()
+  (and hide-ifdef-mode hide-ifdef-hiding
+       (hide-ifdefs t)))
+(add-hook 'after-revert-hook 'hif-before-revert-function)
+
+(defun hide-ifdef-region (start end)
+  "START is the start of a #if or #else form.  END is the ending part.
+Everything including these lines is made invisible."
+  (hif-outline-flag-region start end ?\^M)
+  )
+
+(defun hif-show-ifdef-region (start end)
+  "Everything between START and END is made visible."
+  (hif-outline-flag-region start end ?\n)
+  )
+
+
+
+;===%%SF%% evaluation (Start)  ===
+
+;; It is not useful to set this to anything but `eval'.
+;; In fact, the variable might as well be eliminated.
+(defvar hide-ifdef-evaluator 'eval
+  "The function to use to evaluate a form.
+The evaluator is given a canonical form and returns t if text under
+that form should be displayed.")
+
+(defvar hif-undefined-symbol nil
+  "...is by default considered to be false.")
+
+(defvar hide-ifdef-env nil
+  "An alist of defined symbols and their values.")
+
+
+(defun hif-set-var (var value)
+  "Prepend (var value) pair to hide-ifdef-env."
+  (setq hide-ifdef-env (cons (cons var value) hide-ifdef-env)))
+
+
+(defun hif-lookup (var)
+;  (message "hif-lookup %s" var)
+  (let ((val (assoc var hide-ifdef-env)))
+    (if val
+	(cdr val)
+      hif-undefined-symbol)))
+
+(defun hif-defined (var)
+  (hif-lookup var)
+  ; when #if expressions are fully supported, defined result should be 1
+  ;  (if (assoc var  hide-ifdef-env)
+  ;      1
+  ;    nil)
+)
+
+
+;===%%SF%% evaluation (End)  ===
+
+
+
+;===%%SF%% parsing (Start)  ===
+;;;  The code that understands what ifs and ifdef in files look like.
+
+(defconst hif-cpp-prefix "\\(^\\|\r\\)[ \t]*#[ \t]*")
+(defconst hif-ifndef-regexp (concat hif-cpp-prefix "ifndef"))
+(defconst hif-ifx-regexp (concat hif-cpp-prefix "if\\(n?def\\)?[ \t]+"))
+(defconst hif-else-regexp (concat hif-cpp-prefix "else"))
+(defconst hif-endif-regexp (concat hif-cpp-prefix "endif"))
+(defconst hif-ifx-else-endif-regexp
+  (concat hif-ifx-regexp "\\|" hif-else-regexp "\\|" hif-endif-regexp))
+
+
+(defun hif-infix-to-prefix (token-list)
+  "Convert list of tokens in infix into prefix list"
+;  (message "hif-infix-to-prefix: %s" token-list)
+  (if (= 1 (length token-list))
+      (` (hif-lookup (quote (, (car token-list)))))
+    (hif-parse-if-exp token-list))
+  )
+
+; pattern to match initial identifier, !, &&, ||, (, or ).
+; Added ==, + and -: garyo@avs.com 8/9/94
+(defconst hif-token-regexp "^\\(!\\|&&\\|||\\|[!=]=\\|[()+-]\\|\\w+\\)")
+(defconst hif-end-of-comment "\\*/")
+
+
+(defun hif-tokenize (expr-string)
+  "Separate string into a list of tokens"
+  (let ((token-list nil)
+	(expr-start 0)
+	(expr-length (length expr-string))
+	(current-syntax-table (syntax-table)))
+    (unwind-protect
+	(progn
+	  (set-syntax-table hide-ifdef-syntax-table)
+	  (while (< expr-start expr-length) 
+;	    (message "expr-start = %d" expr-start) (sit-for 1)
+	    (cond
+	     ((string-match "^[ \t]+" expr-string expr-start)
+	      ;; skip whitespace
+	      (setq expr-start (match-end 0))
+	      ;; stick newline in string so ^ matches on the next string-match
+	      (aset expr-string (1- expr-start) ?\n))
+
+	     ((string-match "^/\\*" expr-string expr-start)
+	      (setq expr-start (match-end 0))
+	      (aset expr-string (1- expr-start) ?\n)
+	      (or
+	       (string-match hif-end-of-comment
+			     expr-string expr-start) ; eat comment
+	       (string-match "$" expr-string expr-start)) ; multi-line comment
+	      (setq expr-start (match-end 0))
+	      (aset expr-string (1- expr-start) ?\n))
+
+	     ((string-match "^//" expr-string expr-start)
+	      (string-match "$" expr-string expr-start)
+	      (setq expr-start (match-end 0)))
+
+	     ((string-match hif-token-regexp expr-string expr-start)
+	      (let ((token (substring expr-string expr-start (match-end 0))))
+		(setq expr-start (match-end 0))
+		(aset expr-string (1- expr-start) ?\n)
+;		(message "token: %s" token) (sit-for 1)
+		(setq token-list
+		      (cons
+		       (cond
+			((string-equal token "||") 'or)
+			((string-equal token "&&") 'and)
+			((string-equal token "==") 'equal)
+			((string-equal token "!=") 'hif-notequal)
+			((string-equal token "!")  'not)
+			((string-equal token "defined") 'hif-defined)
+			((string-equal token "(") 'lparen)
+			((string-equal token ")") 'rparen)
+			((string-equal token "+") 'hif-plus)
+			((string-equal token "-") 'hif-minus)
+			(t (intern token)))
+		       token-list))))
+	     (t (error "Bad #if expression: %s" expr-string)))))
+      (set-syntax-table current-syntax-table))
+    (nreverse token-list)))
+
+;;;-----------------------------------------------------------------
+;;; Translate C preprocessor #if expressions using recursive descent.
+;;; This parser is limited to the operators &&, ||, !, and "defined".
+;;; Added ==, !=, +, and -.  Gary Oberbrunner, garyo@avs.com, 8/9/94
+
+(defun hif-parse-if-exp (token-list)
+  "Parse the TOKEN-LIST.  Return translated list in prefix form."
+  (hif-nexttoken)
+  (prog1
+      (hif-expr)
+    (if token ; is there still a token?
+	(error "Error: unexpected token: %s" token))))
+
+(defun hif-nexttoken ()
+  "Pop the next token from token-list into the let variable \"token\"."
+  (setq token (car token-list))
+  (setq token-list (cdr token-list))
+  token)
+
+(defun hif-expr ()
+  "Parse an expression as found in #if.
+       expr : term | expr '||' term."
+  (let ((result (hif-term)))
+    (while (eq  token 'or)
+      (hif-nexttoken)
+      (setq result (list 'or result (hif-term))))
+  result))
+
+(defun hif-term ()
+  "Parse a term : eq-expr | term '&&' eq-expr."
+  (let ((result (hif-eq-expr)))
+    (while (eq token 'and)
+      (hif-nexttoken)
+      (setq result (list 'and result (hif-eq-expr))))
+    result))
+
+(defun hif-eq-expr ()
+  "Parse an eq-expr : math | eq-expr '=='|'!=' math."
+  (let ((result (hif-math))
+	(eq-token nil))
+    (while (or (eq token 'equal) (eq token 'hif-notequal))
+      (setq eq-token token)
+      (hif-nexttoken)
+      (setq result (list eq-token result (hif-math))))
+    result))
+
+(defun hif-math ()
+  "Parse an expression with + or - and simpler things.
+       math : factor | math '+|-' factor."
+  (let ((result (hif-factor))
+	(math-op nil))
+    (while (or (eq  token 'hif-plus) (eq token 'hif-minus))
+      (setq math-op token)
+      (hif-nexttoken)
+      (setq result (list math-op result (hif-factor))))
+  result))
+
+(defun hif-factor ()
+  "Parse a factor: '!' factor | '(' expr ')' | 'defined(' id ')' | id."
+  (cond
+    ((eq token 'not)
+     (hif-nexttoken)
+     (list 'not (hif-factor)))
+
+    ((eq token 'lparen)
+     (hif-nexttoken)
+     (let ((result (hif-expr)))
+       (if (not (eq token 'rparen))
+	   (error "Bad token in parenthesized expression: %s" token)
+	 (hif-nexttoken)
+	 result)))
+
+    ((eq token 'hif-defined)
+     (hif-nexttoken)
+     (if (not (eq token 'lparen))
+	 (error "Error: expected \"(\" after \"defined\""))
+     (hif-nexttoken)
+     (let ((ident token))
+       (if (memq token '(or and not hif-defined lparen rparen))
+	   (error "Error: unexpected token: %s" token))
+       (hif-nexttoken)
+       (if (not (eq token 'rparen))
+	   (error "Error: expected \")\" after identifier"))
+       (hif-nexttoken)
+       (` (hif-defined (quote (, ident))))
+       ))
+
+    (t ; identifier
+      (let ((ident token))
+	(if (memq ident '(or and))
+	    (error "Error: missing identifier"))
+	(hif-nexttoken)
+	(` (hif-lookup (quote (, ident))))
+	))
+    ))
+
+(defun hif-mathify (val)
+  "Treat VAL as a number: if it's t or nil, use 1 or 0."
+  (cond ((eq val t)
+	 1)
+	((null val)
+	 0)
+	(t val)))
+
+(defun hif-plus (a b)
+  "Like ordinary plus but treat t and nil as 1 and 0."
+  (+ (hif-mathify a) (hif-mathify b)))
+(defun hif-minus (a b)
+  "Like ordinary minus but treat t and nil as 1 and 0."
+  (- (hif-mathify a) (hif-mathify b)))
+(defun hif-notequal (a b)
+  "Like (not (equal A B)) but as one symbol."
+  (not (equal a b)))
+
+;;;----------- end of parser -----------------------
+
+
+(defun hif-canonicalize ()
+  "When at beginning of #ifX, returns a Lisp expression for its condition."
+  (save-excursion
+    (let ((negate (looking-at hif-ifndef-regexp)))
+      (re-search-forward hif-ifx-regexp)
+      (let* ((expr-string
+	      (buffer-substring (point)
+				(progn (skip-chars-forward "^\n\r") (point))))
+	     (expr (hif-infix-to-prefix (hif-tokenize expr-string))))
+;	(message "hif-canonicalized: %s" expr)
+	(if negate
+	    (list 'not expr)
+	  expr)))))
+
+
+(defun hif-find-any-ifX ()
+  "Move to next #if..., or #ifndef, at point or after."
+;  (message "find ifX at %d" (point))
+  (prog1
+      (re-search-forward hif-ifx-regexp (point-max) t)
+    (beginning-of-line)))
+
+
+(defun hif-find-next-relevant ()
+  "Move to next #if..., #else, or #endif, after the current line."
+;  (message "hif-find-next-relevant at %d" (point))
+  (end-of-line)
+  ; avoid infinite recursion by only going to beginning of line if match found
+  (if (re-search-forward hif-ifx-else-endif-regexp (point-max) t)
+      (beginning-of-line)))
+
+(defun hif-find-previous-relevant ()
+  "Move to previous #if..., #else, or #endif, before the current line."
+;  (message "hif-find-previous-relevant at %d" (point))
+  (beginning-of-line)
+  ; avoid infinite recursion by only going to beginning of line if match found
+  (if (re-search-backward hif-ifx-else-endif-regexp (point-min) t)
+     (beginning-of-line)))
+
+
+(defun hif-looking-at-ifX ()		;; Should eventually see #if
+  (looking-at hif-ifx-regexp))
+(defun hif-looking-at-endif ()
+  (looking-at hif-endif-regexp))
+(defun hif-looking-at-else ()
+  (looking-at hif-else-regexp))
+
+
+
+(defun hif-ifdef-to-endif ()
+  "If positioned at #ifX or #else form, skip to corresponding #endif."
+;  (message "hif-ifdef-to-endif at %d" (point)) (sit-for 1)
+  (hif-find-next-relevant)
+  (cond ((hif-looking-at-ifX)
+	 (hif-ifdef-to-endif) ; find endif of nested if
+	 (hif-ifdef-to-endif)) ; find outer endif or else
+	((hif-looking-at-else)
+	 (hif-ifdef-to-endif)) ; find endif following else
+	((hif-looking-at-endif)
+	 'done)
+	(t
+	 (error "Mismatched #ifdef #endif pair"))))
+
+
+(defun hif-endif-to-ifdef ()
+  "If positioned at #endif form, skip backward to corresponding #ifX."
+;  (message "hif-endif-to-ifdef at %d" (point))
+  (let ((start (point)))
+    (hif-find-previous-relevant)
+    (if (= start (point))
+	(error "Mismatched #ifdef #endif pair")))
+  (cond ((hif-looking-at-endif)
+	 (hif-endif-to-ifdef) ; find beginning of nested if
+	 (hif-endif-to-ifdef)) ; find beginning of outer if or else
+	((hif-looking-at-else)
+	 (hif-endif-to-ifdef))
+	((hif-looking-at-ifX)
+	 'done)
+	(t)))			; never gets here
+
+
+(defun forward-ifdef (&optional arg)
+  "Move point to beginning of line of the next ifdef-endif.
+With argument, do this that many times."
+  (interactive "p")
+  (or arg (setq arg 1))
+  (if (< arg 0)
+      (backward-ifdef (- arg)))
+  (while (< 0 arg)
+    (setq arg (- arg))
+    (let ((start (point)))
+      (if (not (hif-looking-at-ifX))
+	  (hif-find-next-relevant))
+      (if (hif-looking-at-ifX)
+	  (hif-ifdef-to-endif)
+	(goto-char start)
+	(error "No following #ifdef")
+	))))
+
+
+(defun backward-ifdef (&optional arg)
+  "Move point to beginning of the previous ifdef-endif.
+With argument, do this that many times."
+  (interactive "p")
+  (or arg (setq arg 1))
+  (if (< arg 0)
+      (forward-ifdef (- arg)))
+  (while (< 0 arg)
+    (setq arg (1- arg))
+    (beginning-of-line)
+    (let ((start (point)))
+      (if (not (hif-looking-at-endif))
+	  (hif-find-previous-relevant))
+      (if (hif-looking-at-endif)
+	  (hif-endif-to-ifdef)
+	(goto-char start)
+	(error "No previous #ifdef")))))
+
+
+(defun down-ifdef ()
+  "Move point to beginning of nested ifdef or else-part."
+    (interactive)
+    (let ((start (point)))
+      (hif-find-next-relevant)
+      (if (or (hif-looking-at-ifX) (hif-looking-at-else))
+	  ()
+	(goto-char start)
+	(error "No following #ifdef"))))
+
+
+(defun up-ifdef ()
+  "Move point to beginning of enclosing ifdef or else-part."
+  (interactive)
+  (beginning-of-line)
+  (let ((start (point)))
+    (if (not (hif-looking-at-endif))
+	(hif-find-previous-relevant))
+    (if (hif-looking-at-endif)
+	(hif-endif-to-ifdef))
+      (if (= start (point))
+	  (error "No previous #ifdef"))))
+
+(defun next-ifdef (&optional arg)
+  "Move to the beginning of the next #ifX, #else, or #endif.
+With argument, do this that many times."
+  (interactive "p")
+  (or arg (setq arg 1))
+  (if (< arg 0)
+      (previous-ifdef (- arg)))
+  (while (< 0 arg)
+    (setq arg (1- arg))
+    (hif-find-next-relevant)
+    (if (eolp)
+	(progn
+	  (beginning-of-line)
+	  (error "No following #ifdefs, #elses, or #endifs")))))
+
+(defun previous-ifdef (&optional arg)
+  "Move to the beginning of the previous #ifX, #else, or #endif.
+With argument, do this that many times."
+  (interactive "p")
+  (or arg (setq arg 1))
+  (if (< arg 0)
+      (next-ifdef (- arg)))
+  (while (< 0 arg)
+    (setq arg (1- arg))
+    (let ((start (point)))
+      (hif-find-previous-relevant)
+      (if (= start (point))
+	  (error "No previous #ifdefs, #elses, or #endifs")))))
+
+
+;===%%SF%% parsing (End)  ===
+
+
+;===%%SF%% hide-ifdef-hiding (Start)  ===
+
+
+;;; A range is a structure with four components:
+;;; ELSE-P	True if there was an else clause for the ifdef.
+;;; START	The start of the range. (beginning of line)
+;;; ELSE	The else marker (beginning of line)
+;;;			Only valid if ELSE-P is true.
+;;; END		The end of the range.  (beginning of line)
+
+(defun hif-make-range (else-p start end &optional else)
+  (list else-p start else end))
+
+(defun hif-range-else-p (range)  (elt range 0))
+(defun hif-range-start (range) (elt range 1))
+(defun hif-range-else (range) (elt range 2))
+(defun hif-range-end (range) (elt range 3))
+
+
+
+;;; Find-Range
+;;; The workhorse, it delimits the #if region.  Reasonably simple:
+;;; Skip until an #else or #endif is found, remembering positions.  If
+;;; an #else was found, skip some more, looking for the true #endif.
+
+(defun hif-find-range ()
+  "Returns a Range structure describing the current #if region.
+Point is left unchanged."
+;  (message "hif-find-range at %d" (point))
+  (save-excursion
+    (beginning-of-line)
+    (let ((start (point))
+	  (else-p nil)
+	  (else nil)
+	  (end nil))
+      ;; Part one.  Look for either #endif or #else.
+      ;; This loop-and-a-half dedicated to E. Dijkstra.
+      (hif-find-next-relevant)
+      (while (hif-looking-at-ifX)		; Skip nested ifdef
+	(hif-ifdef-to-endif)
+	(hif-find-next-relevant))
+      ;; Found either a #else or an #endif.
+      (cond ((hif-looking-at-else)
+	     (setq else-p t)
+	     (setq else (point)))
+	    (t
+	     (setq end (point)) ; (save-excursion (end-of-line) (point))
+	     ))
+      ;; If found #else, look for #endif.
+      (if else-p
+	  (progn
+	    (hif-find-next-relevant)
+	    (while (hif-looking-at-ifX)	; Skip nested ifdef
+	      (hif-ifdef-to-endif)
+	      (hif-find-next-relevant))
+	    (if (hif-looking-at-else)
+		(error "Found two elses in a row?  Broken!"))
+	    (setq end (point))  ; (save-excursion (end-of-line) (point))
+	    ))
+      (hif-make-range else-p start end else))))
+
+	  
+;;; A bit slimy.
+;;; NOTE:  If there's an #ifdef at the beginning of the file, we can't
+;;; hide it.  There's no previous newline to replace.  If we added
+;;; one, we'd throw off all the counts.  Feh.
+
+(defun hif-hide-line (point)
+  "Hide the line containing point.  Does nothing if `hide-ifdef-lines' is nil."
+  (if hide-ifdef-lines
+      (save-excursion
+	(goto-char point)
+	(let ((modp (buffer-modified-p)))
+	  (unwind-protect
+	      (progn
+		(beginning-of-line)
+		(if (not (= (point) 1))
+		    (hide-ifdef-region (1- (point)) (point))))
+	    (set-buffer-modified-p modp))
+	  ))
+    ))
+		  
+
+;;;  Hif-Possibly-Hide
+;;;  There are four cases.  The #ifX expression is "taken" if it
+;;;  the hide-ifdef-evaluator returns T.  Presumably, this means the code
+;;;  inside the #ifdef would be included when the program was
+;;;  compiled.  
+;;;
+;;;  Case 1:  #ifX taken, and there's an #else.
+;;;	The #else part must be hidden.  The #if (then) part must be
+;;;	processed for nested #ifX's.
+;;;  Case 2:  #ifX taken, and there's no #else.
+;;;	The #if part must be processed for nested #ifX's.
+;;;  Case 3:  #ifX not taken, and there's an #else.
+;;;	The #if part must be hidden.  The #else part must be processed
+;;;	for nested #ifs.
+;;;  Case 4:  #ifX not taken, and there's no #else.
+;;;	The #ifX part must be hidden.
+;;;
+;;;  Further processing is done by narrowing to the relevant region
+;;;  and just recursively calling hide-ifdef-guts.
+;;;
+;;;  When hif-possibly-hide returns, point is at the end of the
+;;;  possibly-hidden range.
+
+(defun hif-recurse-on (start end)
+  "Call `hide-ifdef-guts' after narrowing to end of START line and END line."
+  (save-excursion
+    (save-restriction
+      (goto-char start)
+      (end-of-line)
+      (narrow-to-region (point) end)
+      (hide-ifdef-guts))))
+
+(defun hif-possibly-hide ()
+  "Called at #ifX expression, this hides those parts that should be hidden.
+It uses the judgement of `hide-ifdef-evaluator'."
+;  (message "hif-possibly-hide") (sit-for 1)
+    (let ((test (hif-canonicalize))
+	  (range (hif-find-range)))
+;      (message "test = %s" test) (sit-for 1)
+      
+      (hif-hide-line (hif-range-end range))
+      (if (funcall hide-ifdef-evaluator test)
+	  (cond ((hif-range-else-p range) ; case 1
+		 (hif-hide-line (hif-range-else range))
+		 (hide-ifdef-region (hif-range-else range) 
+				    (1- (hif-range-end range)))
+		 (hif-recurse-on (hif-range-start range)
+				 (hif-range-else range)))
+		(t ; case 2
+		 (hif-recurse-on (hif-range-start range)
+				 (hif-range-end range))))
+	(cond ((hif-range-else-p range) ; case 3
+	       (hif-hide-line (hif-range-else range))
+	       (hide-ifdef-region (hif-range-start range)
+				  (1- (hif-range-else range)))
+	       (hif-recurse-on (hif-range-else range)
+			       (hif-range-end range)))
+	      (t ; case 4
+	       (hide-ifdef-region (point)
+				  (1- (hif-range-end range))))
+	      ))
+      (hif-hide-line (hif-range-start range))	; Always hide start.
+      (goto-char (hif-range-end range))
+      (end-of-line)
+      ))
+
+
+
+(defun hide-ifdef-guts ()
+  "Does most of the work of `hide-ifdefs'.
+It does not do the work that's pointless to redo on a recursive entry."
+;  (message "hide-ifdef-guts")
+  (save-excursion
+    (goto-char (point-min))
+    (while (hif-find-any-ifX)
+      (hif-possibly-hide))))
+
+;===%%SF%% hide-ifdef-hiding (End)  ===
+
+
+;===%%SF%% exports (Start)  ===
+
+;;;###autoload
+(defvar hide-ifdef-initially nil
+  "*Non-nil means call `hide-ifdefs' when Hide-Ifdef mode is first activated.")
+
+;;;###autoload
+(defvar hide-ifdef-read-only nil
+  "*Set to non-nil if you want buffer to be read-only while hiding text.")
+
+(defvar hif-outside-read-only nil
+  "Internal variable.  Saves the value of `buffer-read-only' while hiding.")
+
+;;;###autoload
+(defvar hide-ifdef-lines nil
+  "*Non-nil means hide the #ifX, #else, and #endif lines.")
+
+(defun hide-ifdef-toggle-read-only ()
+  "Toggle hide-ifdef-read-only."
+  (interactive)
+  (setq hide-ifdef-read-only (not hide-ifdef-read-only))
+  (message "Hide-Read-Only %s"
+	   (if hide-ifdef-read-only "ON" "OFF"))
+  (if hide-ifdef-hiding
+      (setq buffer-read-only (or hide-ifdef-read-only hif-outside-read-only)))
+  ;; XEmacs change
+  (redraw-modeline))
+
+(defun hide-ifdef-toggle-outside-read-only ()
+  "Replacement for `toggle-read-only' within Hide-Ifdef mode."
+  (interactive)
+  (setq hif-outside-read-only (not hif-outside-read-only))
+  (message "Read only %s"
+	   (if hif-outside-read-only "ON" "OFF"))
+  (setq buffer-read-only
+	(or (and hide-ifdef-hiding hide-ifdef-read-only)
+	    hif-outside-read-only)
+	)
+  ;; XEmacs change
+  (redraw-modeline))
+
+      
+(defun hide-ifdef-define (var)
+  "Define a VAR so that #ifdef VAR would be included."
+  (interactive "SDefine what? ")
+  (hif-set-var var 1)
+  (if hide-ifdef-hiding (hide-ifdefs)))
+
+(defun hide-ifdef-undef (var)
+  "Undefine a VAR so that #ifdef VAR would not be included."
+  (interactive "SUndefine what? ")
+  (hif-set-var var nil)
+  (if hide-ifdef-hiding (hide-ifdefs)))
+
+
+(defun hide-ifdefs (&optional nomsg)
+  "Hide the contents of some #ifdefs.  
+Assume that defined symbols have been added to `hide-ifdef-env'.  
+The text hidden is the text that would not be included by the C
+preprocessor if it were given the file with those symbols defined.
+
+Turn off hiding by calling `show-ifdefs'."
+
+  (interactive)
+  (message "Hiding...")
+  (setq hif-outside-read-only buffer-read-only)
+  (if (not hide-ifdef-mode)
+      (hide-ifdef-mode 1)) ; turn on hide-ifdef-mode
+  (if hide-ifdef-hiding
+      (show-ifdefs))			; Otherwise, deep confusion.
+  (let ((inhibit-read-only t))
+    (setq selective-display t)
+    (setq hide-ifdef-hiding t)
+    (hide-ifdef-guts))
+  (setq buffer-read-only (or hide-ifdef-read-only hif-outside-read-only))
+  (or nomsg
+      (message "Hiding done")))
+
+
+(defun show-ifdefs ()
+  "Cancel the effects of `hide-ifdef': show the contents of all #ifdefs."
+  (interactive)
+  (setq buffer-read-only hif-outside-read-only)
+  (setq selective-display nil)	; defaults
+  (let ((inhibit-read-only t))
+    (hif-show-all))
+  (setq hide-ifdef-hiding nil))
+
+
+(defun hif-find-ifdef-block ()
+  "Utility for hide and show `ifdef-block'.
+Set top and bottom of ifdef block."
+  (let (max-bottom)
+  (save-excursion
+    (beginning-of-line)
+    (if (not (or (hif-looking-at-else) (hif-looking-at-ifX)))
+	(up-ifdef))
+    (setq top (point))
+    (hif-ifdef-to-endif)
+    (setq max-bottom (1- (point))))
+  (save-excursion
+    (beginning-of-line)
+    (if (not (hif-looking-at-endif))
+	(hif-find-next-relevant))
+    (while (hif-looking-at-ifX)
+      (hif-ifdef-to-endif)
+      (hif-find-next-relevant))
+    (setq bottom (min max-bottom (1- (point)))))))
+
+
+(defun hide-ifdef-block ()
+  "Hide the ifdef block (true or false part) enclosing or before the cursor."
+  (interactive)
+  (if (not hide-ifdef-mode)
+      (hide-ifdef-mode 1))
+  (setq selective-display t)
+  (let (top bottom (inhibit-read-only t))
+    (hif-find-ifdef-block) ; set top and bottom - dynamic scoping
+    (hide-ifdef-region top bottom)
+    (if hide-ifdef-lines
+	(progn
+	  (hif-hide-line top)
+	  (hif-hide-line (1+ bottom))))
+    (setq hide-ifdef-hiding t))
+  (setq buffer-read-only (or hide-ifdef-read-only hif-outside-read-only)))
+
+
+(defun show-ifdef-block ()
+  "Show the ifdef block (true or false part) enclosing or before the cursor."
+  (interactive)
+  (let ((inhibit-read-only t))
+    (if hide-ifdef-lines
+	(save-excursion
+	  (beginning-of-line)
+	  (hif-show-ifdef-region (1- (point)) (progn (end-of-line) (point))))
+
+      (let (top bottom)
+	(hif-find-ifdef-block)
+	(hif-show-ifdef-region (1- top) bottom)))))
+
+
+;;;  definition alist support
+
+(defvar hide-ifdef-define-alist nil
+  "A global assoc list of pre-defined symbol lists")
+
+(defun hif-compress-define-list (env)
+  "Compress the define list ENV into a list of defined symbols only."
+  (let ((defs (mapcar '(lambda (arg)
+			 (if (hif-lookup (car arg)) (car arg)))
+		      env))
+	(new-defs nil))
+    (while defs
+      (if (car defs)
+	  (setq new-defs (cons (car defs) new-defs)))
+      (setq defs (cdr defs)))
+    new-defs))
+