;;;#ident "@(#):smail:RELEASE-3_2_0_120:emacs.el,v 1.1 2003/12/15 02:52:05 woods Exp"
;;;
;;; These are some suggestions about how best to make use of emacs when editing
;;; Smail source files.
;;;
;;; For the full story see the latest version of the .emacs.el file inside the
;;; following archive:
;;;
;;;	ftp://ftp.weird.com/pub/local/dotfiles.tar.gz
;;;

;;; first some environment detection...
;;;
(defvar init-emacs-type
  (cond ((boundp 'emacs-major-version)	; first available in 19.23
	 emacs-major-version)
	((or (and (fboundp 'epoch::version)
		  (symbol-value 'epoch::version))
	     (string-lessp emacs-version "19"))
	 18)				; was there ever anything less?
	(t 19))				; what else could it be?
  "Emacs major version for testing compatibility.")

(if (<= init-emacs-type 19)
    (progn
      (message "Not running emacs v20 or newer I see -- you may have trouble with this .emacs!")
      (sit-for 5)))

(if (>= init-emacs-type 20)
    (setq inhibit-eol-conversion t))	; show M$ crap for what it is....

;;; stolen by way of Len Tower from Noah Freidman from /home/fsf/friedman/etc/init/emacs/init.el
(defun emacs-version-get-component (component)
  (let ((old-match-data (match-data))
        (version 0)
        (regexp (cond
                 ((eq 'major component) "^\\([0-9]+\\)")
                 ((eq 'minor component) "^[0-9]+\\.\\([0-9]+\\)")
                 ((eq 'build component) "^[0-9]+\\.[0-9]+\\.\\([0-9]+\\)"))))
    (unwind-protect
        (and (string-match regexp emacs-version)
             (setq version
                   (string-to-int (substring emacs-version
                                             (match-beginning 1)
                                             (match-end 1)))))
      (store-match-data old-match-data))
    version))

(defvar emacs-version-major (emacs-version-get-component 'major)
  "Major version number for this Emacs.")
(defvar emacs-version-minor (emacs-version-get-component 'minor)
  "Minor version number for this Emacs.")
(defvar emacs-version-build (emacs-version-get-component 'build)
  "Build number for this Emacs.")
;;; end by Noah Freidman from /home/fsf/friedman/etc/init/emacs/init.el

;;; create a safety-net
;;;
(setq backup-by-copying nil)		; rename is safer and faster...
(setq backup-by-copying-when-linked t)	; ... but when files are linked...
(if (= (user-uid) 0)
    (setq backup-by-copying-when-mismatch t)) ; also if root and not owner so
					      ; as not to change the ownership

;;; some general things needed below
;;;
(setq-default case-fold-search nil)	; unless set, don't ignore case
(setq-default indent-tabs-mode t)	; allow tabs in indentation
(setq-default require-final-newline 1)	; needed by some unix programs
(if (< init-emacs-type 21)
    (defvar indicate-empty-lines))
(setq-default indicate-empty-lines t)	; show which lines are past the EOF
(setq default-tab-width 8)		; a tab is a tab is a tab is a tab....

(setq sentence-end
      "[.?!][]\"')}]*\\($\\| $\\|\t\\|  \\)[ \t\n]*") ; also to make sure!
(setq sentence-end-double-space t)	; just to be absolutely sure!
(if (< init-emacs-type 21)
    (defvar tab-always-indent))
(setq tab-always-indent nil)		; silly

;;;; ----------
;;;; some default key re-binding....
;;;;
;;;; NOTE:  You don't have to use the following when editing Smail files of
;;;; course, but there are a couple of bindings set in the hooks below which
;;;; assume you are using it.

;;; first off, we do some fancy stuff to make C-h work "properly," but still
;;; have good access to the help functions!
;;
;; NOTE: this *should* work by simply reading termio for current erase char.
;;
;; As of emacs-21.2 there's a note in the NEWS file which says "** On
;; terminals whose erase-char is ^H (Backspace), Emacs now uses
;; normal-erase-is-backspace-mode."  Unfortunately this does exactly the
;; wrong thing, and it does it in a totally bizzare and very stupid way.
;;
;; Remember to call override-local-key-settings in the appropriate hooks to fix
;; up modes which violate global user preferences....
;;
(if (and (>= init-emacs-type 21)
	 (>= emacs-version-minor 2))
    ;; grrr.... do something with that stupid broken poor useless excuse for
    ;; a feature, normal-erase-is-backspace-mode....
    (setq keyboard-translate-table nil))
(global-set-key "\C-h" 'delete-backward-char)
(global-set-key "\C-?" 'delete-char)
(global-set-key "\e\C-h" 'backward-kill-word)
(global-set-key "\e\C-?" 'kill-word)

;;; OK, now we diddle with help....
;;
;; Oddly, the help interface in emacs is extremely scatter-brained, with
;; several slightly different ways of doing the same thing.  This is probably
;; due to the fact that several different programmers have implemented various
;; bits and pieces of the help systems.  See help.el and help-macro.el, but try
;; not to tear your hair out when you find out help-event-list in 19.34 is
;; essentially bogus, since it is simply an extension to a "standard" list.
;;
;; Remember to call override-local-key-settings in the appropriate hooks to fix
;; up modes which violate global user preferences....
;;
(global-set-key [f1] 'help-command)	; first do this for 19.28.
(global-set-key "\e?" 'help-command)	; this is the first step to set up help
(global-set-key "\e?F" 'view-emacs-FAQ)	; in 19.34 it needs more help...
;; should help-char be just ? instead?
(setq help-char ?\M-?)			; this should "fix" the rest.

;;; I USUALLY EXPECT THE BACKSPACE KEY TO WORK LIKE AN ASCII BACKSPACE!
;;
;; For some entirely un-fathomable reason the default function bindings make
;; the 'backspace' and 'delete' keys synonymous!
;;
(define-key function-key-map [backspace] [?\C-h])
(define-key function-key-map [M-backspace] [?\M-\C-h])
;;(define-key function-key-map [C-backspace] [?\C-h]) ; sometimes *is* DEL....

;;; OK, that's the end of the stuff to fix GNU Emacs' C-h brain damage.

;;; some helper functions....
;;;
;;; This one could probably be rewritten to use mapcar
;;;
(defun elisp-file-in-loadpath-p (file-name)
  "Returns t if there is an emacs lisp-library of the name FILENAME in
the load-path list. Matching is first done by looking for the file
with an .elc extension, an .el extension, and finally with no
extension at all, and returning t if any of the three are found. Nil
is returned otherwise."
  (let ((extension-list (list ".elc" ".el" ""))
        (file-found-p nil)
        name-to-try)
    (while (and (not file-found-p) (not (null extension-list)))
      (setq name-to-try (concat file-name (car extension-list)))
      (setq extension-list (cdr extension-list))
      (setq file-found-p (file-in-loadpath-p name-to-try)))
    (eval 'file-found-p)))

(defun file-in-loadpath-p (file-name)
  "Returns t if the string argument FILENAME is a file name present in a
directory in the load-path list, otherwise returns nil."
  (file-in-pathlist-p file-name load-path))

(defun file-in-pathlist-p (file-name path-list)
  "Returns t if the string FILENAME is a file name which occurs in a
directory in the list PATHLIST, otherwise nil."
  (let (try-path (file-found-in-path-p nil))
    (while (not (or file-found-in-path-p (null path-list)))
      (setq try-path (car path-list)
            path-list (cdr path-list))
      (if (file-exists-p (concat try-path "/" file-name)) ; path-separator :-)
          (setq file-found-in-path-p t)))
    (eval 'file-found-in-path-p)))


;;; GNU-Emacs' ideas about formatting C code really suck!  Let's stick to doing
;;; things the good old standard K&R way!!!!
;;;
;;; For reference my .indent.pro (for BSD indent) says:
;;;
;;;  -bad -bap -bc -br -nbs -c49 -cd33 -ncdb -ce -cli0 -d0 -di16 -ndj -ei -neei
;;;  -nfc1 -i8 -ip -l256 -lp -npcs -psl -sc -nsob -Tptrdiff_t -Tsize_t
;;;  -Tssize_t -Toff_t -Ttime_t -Tclock_t -Tsocklen_t -Tbool_t -Tenum_t
;;;  -Tu_char -Tu_short -Tu_int -Tu_long -Tuchar -Tushort -Tuint -Tulong
;;;  -Tunchar -Tquad_t -Tu_quad_t -Tqaddr_t -Tlonglong_t -Tu_longlong_t
;;;  -Tregoff_t -Twchar_t -Tint8_t -Tuint8_t -Tu_int8_t -Tint16_t -Tuint16_t
;;;  -Tu_int16_t -Tint32_t -Tuint32_t -Tu_int32_t -Tint64_t -Tuint64_t
;;;  -Tu_int64_t -Tintptr_t -Tuintptr_t -Tva_list -Tmode_t -Toff_t -Tpid_t
;;;  -Tuid_t -Tgid_t -Trlim_t
;;;
;;; NOTE: Someday I _think_ I want a simple flag I can toggle in a file's local
;;; variables to turn off use of tab characters and do all indentation and
;;; alignment with spaces only.

(require 'cc-mode)

(setq c-font-lock-extra-types
      '("FILE"
	"fd_set"
	"jmp_buf"
	"va_list"
	"\\sw+_t"
	"t_\\sw+"
	"u_\\sw+"
	"uchar"
	"uint"
	"ulong"
	"unchar"
	"ushort"))

(defconst my-c-style
  '((c-backslash-column . 78)
    (c-basic-offset . 8)
    (c-block-comment-prefix . "* ")
    (c-cleanup-list . (brace-else-brace
		       brace-elseif-brace
		       scope-operator)) ; (scope-operator)
    (c-comment-continuation-stars . "* ")
    (c-comment-only-line-offset . (0 . 0))
    ;; ACTION can be either a function symbol or a list containing any
    ;; combination of the symbols `before' or `after'.  If the list is empty,
    ;; no newlines are inserted either before or after the brace.
    (c-hanging-braces-alist . ((block-open . (after))
			       (block-close . (before))
			       (brace-list-open . nil)
			       (brace-list-close . nil)
			       (brace-list-intro . nil)
			       (brace-list-entry . nil)
			       (class-open . (after))
			       (class-close . nil)
			       (defun-open . (before after))
			       (defun-close . (before))
			       (inline-open . nil)
			       (inline-close . nil)
			       (statement-case-open . nil)
			       (substatement-open . nil)))
    (c-hanging-colons-alist . ((member-init-intro before)
			       (inher-intro)
			       (case-label after)
			       (label after)
			       (access-label after)))
    (c-label-minimum-indentation . 0)
    ;; an OFFSET is nil; an inteter (usually zero); one of the symbols:  `+',
    ;; `-', `++', `--', `*', or `/' (a positive or negative multiple of
    ;; `c-basic-offset' is added; 1, -1, 2, -2, 0.5, and -0.5, respectively); a
    ;; vector; a function; or a list.
    (c-offsets-alist . ((arglist-close . c-lineup-close-paren) ; +
			(arglist-cont-nonempty . c-lineup-arglist) ; +
			(arglist-intro . c-lineup-arglist-intro-after-paren) ; +
			(block-open . -) ; 0
			(func-decl-cont . 0) ; +
			(inline-open . 0) ; +
                        (statement-case-open . *) ; 0
			(statement-cont . c-lineup-math) ; +
			(substatement-open . 0)))) ; +
  "My PERSONAL C Style, similar to NetBSD KNF.")
(c-add-style "PERSONAL" my-c-style nil)

(defconst smail-c-style
  (append my-c-style '((c-basic-offset . 4)))
  "Smail C Style; my personal style, but at offset 4.")
(c-add-style "SMAIL" smail-c-style nil)

(defconst my-awk-style
  '((c-backslash-column . 78)
    (c-basic-offset . 8)
    (c-block-comment-prefix . "# ")
    (c-cleanup-list . (brace-else-brace
		       brace-elseif-brace
		       scope-operator)) ; (scope-operator)
    (c-comment-continuation-stars . "# ")
    (c-comment-only-line-offset . (0 . 0))
    (c-comment-prefix-regexp . "# *")
    (c-comment-start-regexp . "#[ 	]*")
    ;; ACTION can be either a function symbol or a list containing any
    ;; combination of the symbols `before' or `after'.  If the list is empty,
    ;; no newlines are inserted either before or after the brace.
    (c-hanging-braces-alist . ((block-open . nil)
			       (block-close . (before))
			       (brace-list-open . nil)
			       (brace-list-close . nil)
			       (brace-list-intro . nil)
			       (brace-list-entry . nil)
			       (class-open . (after))
			       (class-close . nil)
			       (defun-open . (after))
			       (defun-close . (before))
			       (defun-block-intro . (after))
			       (inline-open . nil)
			       (inline-close . nil)
			       (statement-case-open . nil)
			       (substatement-open . nil)))
    (c-hanging-colons-alist . ((member-init-intro before)
			       (inher-intro)
			       (case-label after)
			       (label after)
			       (access-label after)))
    (c-label-minimum-indentation . 0)
    ;; an OFFSET is nil; an inteter (usually zero); one of the symbols:  `+',
    ;; `-', `++', `--', `*', or `/' (a positive or negative multiple of
    ;; `c-basic-offset' is added; 1, -1, 2, -2, 0.5, and -0.5, respectively); a
    ;; vector; a function; or a list.
    (c-offsets-alist . ((arglist-close . c-lineup-close-paren) ; +
			(arglist-cont-nonempty . c-lineup-arglist) ; +
			(arglist-intro . c-lineup-arglist-intro-after-paren) ; +
			(block-open . -) ; 0
			(func-decl-cont . 0) ; +
			(inline-open . 0) ; +
                        (statement-case-open . *) ; 0
			(statement-cont . c-lineup-math) ; +
			(substatement-open . 0)))) ; +
  "My PERSONAL AWK Style, similar to my-c-style.")
(c-add-style "PERSONAL-AWK" my-awk-style nil)

;; XXX c-default-style does not work properly for awk-mode in cc-mode 5.28
;; (e.g. in 21.3) because awk-mode is just a derived mode.  See the setting of
;; awk-mode-hook below for the attempt to hack around this bug.
;;
(setq c-default-style
      '((awk-mode . "PERSONAL-AWK")
	(c-mode . "PERSONAL")
	(other . "PERSONAL")))

(defun override-default-variable-settings ()
  "User defined function.  Intended to be called within various hooks to
override the value of buffer-local variables whose default values
might have been overridden by the major mode."
  (setq case-fold-search t		; allow case-insensitive searches
        indent-tabs-mode t		; allow tabs in indentation
        selective-display nil))		; don't allow selective display

(defun override-local-key-settings ()
  "User defined function.  Intended to be called within various hooks to
override the value of buffer-local key map settings which may have been
overridden without consideration by the major mode."
  (local-set-key "\C-?" 'delete-char)	; many modes
  (local-set-key "\C-h" 'delete-backward-char)	; sh-mode
  ;; the rest are *not* overridden by cc-mode, but are by c-mode
  (local-set-key "\e\C-h" 'backward-kill-word) ; text-mode
  (local-set-key "\e?" 'help-command)	; nroff-mode
  (local-set-key "\eh" 'mark-c-function)
  (local-set-key "\e\C-?" 'kill-word)
  (local-set-key "\e\C-e" 'compile)
  ;; try this on for size...
  (local-set-key "\C-x\e\C-e" 'recompile)
  )

(defun my-c-mode-common-hook ()
  "My setup hook to be called by all CC Mode modes for common initializations."

  ;; other customizations
  (setq tab-width 8)			; normal, standard, default TAB chars
  (setq fill-column 79)
  (setq comment-column 40)
  (if (< init-emacs-type 21)
    (defvar comment-style))
  (setq comment-style 'extra-line)	; not used, but maybe someday?
  (setq indent-tabs-mode t)		; only use tabs

  (if (elisp-file-in-loadpath-p "filladapt")
      (progn
	(require 'filladapt)
	(c-setup-filladapt)
	;; we supposedly can't autoload this thing, yet that means this
	;; function will not be defined at compile time...
	(turn-on-filladapt-mode)))

  ;; CC Mode things that are not style variables...
  (setq c-echo-syntactic-information-p nil)
  (setq c-electric-pound-behavior '(alignleft)) ; nil
  (setq c-recognize-knr-p t)		; yes, PLEASE!
  (setq c-tab-always-indent nil)	; insert tabs if not in left margin

  (c-toggle-auto-state 1)		; try this on for size!

  ;; keybindings for all of the supported languages.  We can put these in
  ;; c-mode-base-map because awk-mode-map, c-mode-map, c++-mode-map,
  ;; objc-mode-map, java-mode-map, idl-mode-map, pike-mode-map, and so on
  ;; inherit from it.
  (define-key c-mode-base-map "\C-m" 'c-context-line-break)
  (define-key c-mode-base-map "\ej" 'c-fill-paragraph)

  ;; even cc-mode is sometimes too over-bearing.  It seems to
  ;; insist re-setting some key bindings without regard to the
  ;; global key map.
  (override-local-key-settings)
  (override-default-variable-settings))

(add-hook 'c-mode-common-hook 'my-c-mode-common-hook)

;; Derived modes don't have their major-mode (or mode-name) set until after the
;; parent mode has been initialized.  For example this causes c-default-style
;; to be useless with any modes derived from c-mode.  This silly function
;; attempts to work around that bug and can be used in the initialization hook
;; for any such mode derived from c-mode (such as awk-mode).
;;
(defun my-derived-c-mode-hook ()
  "Silly setup hook to be called by modes derived from c-mode."
  (let ((style (if (stringp c-default-style)
		   c-default-style
		 (or (cdr (assq major-mode c-default-style))
		     (cdr (assq 'other c-default-style))
		     "gnu"))))
    (c-set-style style 't)))

;; In 21.3 awk-mode is a derived mode of c-mode.
;;
(add-hook 'awk-mode-hook 'my-derived-c-mode-hook)

;; the real thing, in 19.30(?) and above
(if (elisp-file-in-loadpath-p "sh-script")
    (progn
      ;; to quiet the v19 bytecompiler...
      (defvar sh-alias-alist)
      (defvar sh-indentation)
      (defvar sh-basic-offset)
      (defvar sh-learn-basic-offset)
      (defvar sh-indent-comment)
      (defvar sh-indent-for-case-label)
      (defvar sh-indent-for-case-alt)
      (defvar sh-indent-for-do)
      (defvar sh-indent-for-then)
      (defvar sh-indent-after-switch)
      (defvar sh-indent-after-case)
      (defvar sh-indent-after-do)
      (setq sh-alias-alist
	    '((ksh . posix)		; most shells are really posix
	      (bash2 . posix)
	      (ash . posix)
	      (sh . posix)
	      (sh5 . sh)))
      (setq sh-indentation 8)
      (setq sh-basic-offset 8)
      (setq sh-learn-basic-offset nil)	; never....
      (setq sh-indent-comment t)
      ;; 	+   Indent right by sh-basic-offset
      ;; 	-   Indent left  by sh-basic-offset
      ;; 	++  Indent right twice sh-basic-offset
      ;; 	--  Indent left  twice sh-basic-offset
      ;; 	*   Indent right half sh-basic-offset
      ;; 	/   Indent left  half sh-basic-offset.
      (setq sh-indent-for-case-label 0)
      (setq sh-indent-for-case-alt '+)
      (setq sh-indent-for-do 0)
      (setq sh-indent-after-do '+)
      (setq sh-indent-for-then 0)
      (setq sh-indent-after-case 0)		; for rc
      (setq sh-indent-after-switch 0)		; for rc
      (add-hook 'sh-mode-hook
		(function
		 (lambda ()
		   "Private sh-mode-hook."
		   (override-local-key-settings)
		   (override-default-variable-settings))))))

;;;; ----------
;;;; The end.
