123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697 |
- (eval-when-compile
- (require 'cl)
- (require 'imenu)
- (require 'tempo))
- (defgroup snmp nil
- "Mode for editing SNMP MIB files."
- :group 'data
- :version "20.4")
- (defcustom snmp-special-indent t
- "If non-nil, use a simple heuristic to try to guess the right indentation.
- If nil, then no special indentation is attempted."
- :type 'boolean
- :group 'snmp)
- (defcustom snmp-indent-level 4
- "Indentation level for SNMP MIBs."
- :type 'integer
- :group 'snmp)
- (defcustom snmp-tab-always-indent nil
- "Non-nil means TAB should always reindent the current line.
- A value of nil means reindent if point is within the initial line indentation;
- otherwise insert a TAB."
- :type 'boolean
- :group 'snmp)
- (defcustom snmp-completion-ignore-case t
- "Non-nil means that case differences are ignored during completion.
- A value of nil means that case is significant.
- This is used during Tempo template completion."
- :type 'boolean
- :group 'snmp)
- (defcustom snmp-common-mode-hook nil
- "Hook(s) evaluated when a buffer enters either SNMP or SNMPv2 mode."
- :type 'hook
- :group 'snmp)
- (defcustom snmp-mode-hook nil
- "Hook(s) evaluated when a buffer enters SNMP mode."
- :type 'hook
- :group 'snmp)
- (defcustom snmpv2-mode-hook nil
- "Hook(s) evaluated when a buffer enters SNMPv2 mode."
- :type 'hook
- :group 'snmp)
- (defvar snmp-tempo-tags nil
- "*Tempo tags for SNMP mode.")
- (defvar snmpv2-tempo-tags nil
- "*Tempo tags for SNMPv2 mode.")
- (defvar snmp-font-lock-keywords-1
- (list
-
- '("^[ \t]*\\([a-z][-a-zA-Z0-9]+\\)[ \t]+\\(\\(MODULE-\\(COMPLIANCE\\|IDENTITY\\)\\|OBJECT-\\(COMPLIANCE\\|GROUP\\|IDENTITY\\|TYPE\\)\\|TRAP-\\(GROUP\\|TYPE\\)\\)\\|\\(OBJECT\\)[ \t]+\\(IDENTIFIER\\)[ \t]*::=\\)"
- (1 font-lock-variable-name-face) (3 font-lock-keyword-face nil t)
- (7 font-lock-keyword-face nil t) (8 font-lock-keyword-face nil t))
-
- '("^[ \t]*\\([A-Z][-a-zA-Z0-9]+\\)[ \t]+\\(DEFINITIONS\\)[ \t]*::="
- (1 font-lock-function-name-face) (2 font-lock-keyword-face))
- )
- "Basic SNMP MIB mode expression highlighting.")
- (defvar snmp-font-lock-keywords-2
- (append
- '(("ACCESS\\|BEGIN\\|DE\\(FVAL\\|SCRIPTION\\)\\|END\\|FROM\\|I\\(MPORTS\\|NDEX\\)\\|S\\(TATUS\\|YNTAX\\)"
- (0 font-lock-keyword-face)))
- snmp-font-lock-keywords-1)
- "Medium SNMP MIB mode expression highlighting.")
- (defvar snmp-font-lock-keywords-3
- (append
- '(("\\([^\n]+\\)[ \t]+::=[ \t]+\\(SEQUENCE\\)[ \t]+{"
- (1 font-lock-reference-face) (2 font-lock-keyword-face))
- ("::=[ \t]*{[ \t]*\\([a-z0-9].*[ \t]+\\)?\\([0-9]+\\)[ \t]*}"
- (1 font-lock-reference-face nil t) (2 font-lock-variable-name-face)))
- snmp-font-lock-keywords-2)
- "Gaudy SNMP MIB mode expression highlighting.")
- (defvar snmp-font-lock-keywords snmp-font-lock-keywords-1
- "Default SNMP MIB mode expression highlighting.")
- (defvar snmp-mode-syntax-list nil
- "Predefined types for SYNTAX clauses.")
- (defvar snmp-rfc1155-types
- '("INTEGER" "OCTET STRING" "OBJECT IDENTIFIER" "NULL" "IpAddress"
- "NetworkAddress" "Counter" "Gauge" "TimeTicks" "Opaque")
- "Types from RFC 1155 v1 SMI.")
- (defvar snmp-rfc1213-types
- '("DisplayString")
- "Types from RFC 1213 MIB-II.")
- (defvar snmp-rfc1902-types
- '("INTEGER" "OCTET STRING" "OBJECT IDENTIFIER" "Integer32"
- "IpAddress" "Counter32" "Gauge32" "Unsigned32" "TimeTicks"
- "Opaque" "Counter64")
- "Types from RFC 1902 v2 SMI.")
- (defvar snmp-rfc1903-types
- '("DisplayString" "PhysAddress" "MacAddress" "TruthValue"
- "TestAndIncr" "AutonomousType" "InstancePointer"
- "VariablePointer" "RowPointer" "RowStatus" "TimeStamp"
- "TimeInterval" "DateAndTime" "StorageType" "TDomain"
- "TAddress")
- "Types from RFC 1903 Textual Conventions.")
- (defvar snmp-mode-access-list nil
- "Predefined values for ACCESS clauses.")
- (defvar snmp-rfc1155-access
- '("read-only" "read-write" "write-only" "not-accessible")
- "ACCESS values from RFC 1155 v1 SMI.")
- (defvar snmp-rfc1902-access
- '("read-only" "read-write" "read-create" "not-accessible"
- "accessible-for-notify")
- "ACCESS values from RFC 1155 v1 SMI.")
- (defvar snmp-mode-status-list nil
- "Predefined values for STATUS clauses.")
- (defvar snmp-rfc1212-status
- '("mandatory" "obsolete" "deprecated")
- "STATUS values from RFC 1212 v1 SMI.")
- (defvar snmp-rfc1902-status
- '("current" "obsolete" "deprecated")
- "STATUS values from RFC 1902 v2 SMI.")
- (defvar snmp-mode-abbrev-table nil
- "Abbrev table in use in SNMP mode.")
- (define-abbrev-table 'snmp-mode-abbrev-table ())
- (defvar snmpv2-mode-abbrev-table nil
- "Abbrev table in use in SNMPv2 mode.")
- (define-abbrev-table 'snmpv2-mode-abbrev-table ())
- (defvar snmp-mode-map
- (let ((map (make-sparse-keymap)))
- (define-key map "\177" 'backward-delete-char-untabify)
- (define-key map "\C-c\C-i" 'tempo-complete-tag)
- (define-key map "\C-c\C-f" 'tempo-forward-mark)
- (define-key map "\C-c\C-b" 'tempo-backward-mark)
- map)
- "Keymap used in SNMP mode.")
- (defvar snmp-mode-syntax-table
- (let ((st (make-syntax-table)))
- (modify-syntax-entry ?\\ "\\" st)
- (modify-syntax-entry ?- "_ 1234" st)
- (modify-syntax-entry ?\n ">" st)
- (modify-syntax-entry ?\ ">" st)
- (modify-syntax-entry ?_ "." st)
- (modify-syntax-entry ?: "." st)
- (modify-syntax-entry ?= "." st)
- st)
- "Syntax table used for buffers in SNMP mode.")
- (defun snmp-common-mode (name mode abbrev font-keywords imenu-index tempo-tags)
- (kill-all-local-variables)
-
- (setq mode-name name)
- (setq major-mode mode)
-
- (use-local-map snmp-mode-map)
- (set-syntax-table snmp-mode-syntax-table)
- (setq local-abbrev-table abbrev)
-
- (make-local-variable 'paragraph-start)
- (setq paragraph-start (concat "$\\|" page-delimiter))
- (make-local-variable 'paragraph-separate)
- (setq paragraph-separate paragraph-start)
- (make-local-variable 'paragraph-ignore-fill-prefix)
- (setq paragraph-ignore-fill-prefix t)
-
- (make-local-variable 'comment-start)
- (setq comment-start "-- ")
- (make-local-variable 'comment-start-skip)
- (setq comment-start-skip "--+[ \t]*")
- (make-local-variable 'comment-column)
- (setq comment-column 40)
- (make-local-variable 'parse-sexp-ignore-comments)
- (setq parse-sexp-ignore-comments t)
-
- (if snmp-special-indent
- (set (make-local-variable 'indent-line-function) 'snmp-indent-line))
- (set (make-local-variable 'tab-always-indent) snmp-tab-always-indent)
-
- (make-local-variable 'font-lock-defaults)
- (setq font-lock-defaults (cons font-keywords '(nil nil ((?- . "w 1234")))))
-
- (make-local-variable 'imenu-create-index-function)
- (setq imenu-create-index-function imenu-index)
-
- (tempo-use-tag-list tempo-tags)
- (make-local-variable 'tempo-match-finder)
- (setq tempo-match-finder "\\b\\(.+\\)\\=")
- (make-local-variable 'tempo-interactive)
- (setq tempo-interactive t)
-
- (make-local-variable 'require-final-newline)
- (setq require-final-newline mode-require-final-newline))
- (defun snmp-mode ()
- "Major mode for editing SNMP MIBs.
- Expression and list commands understand all C brackets.
- Tab indents for C code.
- Comments start with -- and end with newline or another --.
- Delete converts tabs to spaces as it moves back.
- \\{snmp-mode-map}
- Turning on snmp-mode runs the hooks in `snmp-common-mode-hook', then
- `snmp-mode-hook'."
- (interactive)
- (snmp-common-mode "SNMP" 'snmp-mode
- snmp-mode-abbrev-table
- '(snmp-font-lock-keywords
- snmp-font-lock-keywords-1
- snmp-font-lock-keywords-2
- snmp-font-lock-keywords-3)
- 'snmp-mode-imenu-create-index
- 'snmp-tempo-tags)
-
- (make-local-variable 'snmp-mode-syntax-list)
- (setq snmp-mode-syntax-list (append snmp-rfc1155-types
- snmp-rfc1213-types
- snmp-mode-syntax-list))
- (make-local-variable 'snmp-mode-access-list)
- (setq snmp-mode-access-list snmp-rfc1155-access)
- (make-local-variable 'snmp-mode-status-list)
- (setq snmp-mode-status-list snmp-rfc1212-status)
-
- (run-mode-hooks 'snmp-common-mode-hook 'snmp-mode-hook))
- (defun snmpv2-mode ()
- "Major mode for editing SNMPv2 MIBs.
- Expression and list commands understand all C brackets.
- Tab indents for C code.
- Comments start with -- and end with newline or another --.
- Delete converts tabs to spaces as it moves back.
- \\{snmp-mode-map}
- Turning on snmp-mode runs the hooks in `snmp-common-mode-hook',
- then `snmpv2-mode-hook'."
- (interactive)
- (snmp-common-mode "SNMPv2" 'snmpv2-mode
- snmpv2-mode-abbrev-table
- '(snmp-font-lock-keywords
- snmp-font-lock-keywords-1
- snmp-font-lock-keywords-2
- snmp-font-lock-keywords-3)
- 'snmp-mode-imenu-create-index
- 'snmpv2-tempo-tags)
-
- (make-local-variable 'snmp-mode-syntax-list)
- (setq snmp-mode-syntax-list (append snmp-rfc1902-types
- snmp-rfc1903-types
- snmp-mode-syntax-list))
- (make-local-variable 'snmp-mode-access-list)
- (setq snmp-mode-access-list snmp-rfc1902-access)
- (make-local-variable 'snmp-mode-status-list)
- (setq snmp-mode-status-list snmp-rfc1902-status)
-
- (run-mode-hooks 'snmp-common-mode-hook 'snmpv2-mode-hook))
- (defvar snmp-macro-open
- "[a-zA-Z][-a-zA-Z0-9]*[ \t]*\\(OBJECT\\|TRAP\\)-\\(TYPE\\|GROUP\\)\
- \\|DESCRIPTION\\|IMPORTS\\|MODULE\\(-IDENTITY\\|-COMPLIANCE\\)\
- \\|.*::=[ \t]*\\(BEGIN\\|TEXTUAL-CONVENTION\\)[ \t]*$")
- (defvar snmp-macro-close
- "::=[ \t]*{\\|\\(END\\|.*[;\"]\\)[ \t]*$")
- (defun snmp-calculate-indent ()
- "Calculate the current line indentation in SNMP MIB code.
- We use a very simple scheme: if the previous non-empty line was a \"macro
- open\" string, add `snmp-indent-level' to it. If it was a \"macro close\"
- string, subtract `snmp-indent-level'. Otherwise, use the same indentation
- as the previous non-empty line. Note comments are considered empty
- lines for the purposes of this function."
- (let ((empty (concat "\\([ \t]*\\)\\(" comment-start-skip "\\|$\\)"))
- (case-fold-search nil))
- (save-excursion
- (while (and (>= (forward-line -1) 0)
- (looking-at empty)))
- (skip-chars-forward " \t")
- (+ (current-column)
-
- (cond ((looking-at snmp-macro-open)
- snmp-indent-level)
-
- ((looking-at snmp-macro-close)
- (- snmp-indent-level))
-
- (t 0))))))
- (defun snmp-indent-line ()
- "Indent current line as SNMP MIB code."
- (let ((indent (snmp-calculate-indent))
- (pos (- (point-max) (point)))
- shift-amt beg)
- (beginning-of-line)
- (setq beg (point))
- (skip-chars-forward " \t")
- (setq shift-amt (- indent (current-column)))
- (if (zerop shift-amt)
- nil
- (delete-region beg (point))
- (indent-to indent))
-
-
- (if (> (- (point-max) pos) (point))
- (goto-char (- (point-max) pos)))))
- (defvar snmp-clause-regexp
- "^[ \t]*\\([a-zA-Z][-a-zA-Z0-9]*\\)[ \t\n]*\
- \\(TRAP-TYPE\\|::=\\|OBJECT\\(-TYPE[ \t\n]+SYNTAX\\|[ \t\n]+IDENTIFIER[ \t\n]*::=\\)\\)")
- (defun snmp-mode-imenu-create-index ()
- (let ((index-alist '())
- (index-oid-alist '())
- (index-tc-alist '())
- (index-table-alist '())
- (index-trap-alist '())
- (case-fold-search nil)
- prev-pos token end)
- (goto-char (point-min))
- (imenu-progress-message prev-pos 0)
-
- (save-match-data
- (while (re-search-forward snmp-clause-regexp nil t)
- (imenu-progress-message prev-pos)
- (setq
- end (match-end 0)
- token (cons (match-string 1)
- (set-marker (make-marker) (match-beginning 1))))
- (goto-char (match-beginning 2))
- (cond ((looking-at "OBJECT-TYPE[ \t\n]+SYNTAX")
- (push token index-alist))
- ((looking-at "OBJECT[ \t\n]+IDENTIFIER[ \t\n]*::=")
- (push token index-oid-alist))
- ((looking-at "::=[ \t\n]*SEQUENCE[ \t\n]*{")
- (push token index-table-alist))
- ((looking-at "TRAP-TYPE")
- (push token index-trap-alist))
- ((looking-at "::=")
- (push token index-tc-alist)))
- (goto-char end)))
-
- (imenu-progress-message prev-pos 100)
- (setq index-alist (nreverse index-alist))
- (and index-tc-alist
- (push (cons "Textual Conventions" (nreverse index-tc-alist))
- index-alist))
- (and index-trap-alist
- (push (cons "Traps" (nreverse index-trap-alist))
- index-alist))
- (and index-table-alist
- (push (cons "Tables" (nreverse index-table-alist))
- index-alist))
- (and index-oid-alist
- (push (cons "Object IDs" (nreverse index-oid-alist))
- index-alist))
- index-alist))
- (require 'tempo)
- (defun snmp-completing-read (prompt table &optional pred require init hist)
- "Read from the minibuffer, with completion.
- Like `completing-read', but the variable `snmp-completion-ignore-case'
- controls whether case is significant."
- (let ((completion-ignore-case snmp-completion-ignore-case))
- (completing-read prompt table pred require init hist)))
- (tempo-define-template "snmp-object-type"
- '(> (P "Object Label: ") " OBJECT-TYPE" n>
- "SYNTAX "
- (if tempo-interactive
- (snmp-completing-read "Syntax: " snmp-mode-syntax-list nil nil)
- p) n>
- "ACCESS "
- (if tempo-interactive
- (snmp-completing-read "Access: " snmp-mode-access-list nil t)
- p) n>
- "STATUS "
- (if tempo-interactive
- (snmp-completing-read "Status: " snmp-mode-status-list nil t)
- p) n>
- "DESCRIPTION" n> "\"" p "\"" n>
- (P "Default Value: " defval t)
- (if (string= "" (tempo-lookup-named 'defval))
- nil
- '(l "DEFVAL { " (s defval) " }" n>))
- "::= { " (p "OID: ") " }" n)
- "objectType"
- "Insert an OBJECT-TYPE macro."
- 'snmp-tempo-tags)
- (tempo-define-template "snmp-table-type"
-
- '(> (P "Table Name: " table)
- (P "Entry Name: " entry t)
- (let* ((entry (tempo-lookup-named 'entry))
- (seq (copy-sequence entry)))
- (aset entry 0 (downcase (aref entry 0)))
- (aset seq 0 (upcase (aref seq 0)))
- (tempo-save-named 'obj-entry entry)
- (tempo-save-named 'seq-entry seq)
- nil)
- " OBJECT-TYPE" n>
- "SYNTAX SEQUENCE OF "
- (s seq-entry) n>
- "ACCESS not-accessible" n>
- "STATUS mandatory" n>
- "DESCRIPTION" n> "\"" p "\"" n>
- "::= { " (p "OID: ") " }" n n>
-
- (s obj-entry) " OBJECT-TYPE" n>
- "SYNTAX " (s seq-entry) n>
- "ACCESS not-accessible" n>
- "STATUS mandatory" n>
- "DESCRIPTION" n> "\"" p "\"" n>
- "INDEX { " (p "Index List: ") " }" n>
- "::= {" (s table) " 1 }" n n>
-
- (s seq-entry) " ::= SEQUENCE {" n> p n> "}" n)
- "tableType"
- "Insert an SNMP table."
- 'snmp-tempo-tags)
- (tempo-define-template "snmpv2-object-type"
- '(> (P "Object Label: ") " OBJECT-TYPE" n>
- "SYNTAX "
- (if tempo-interactive
- (snmp-completing-read "Syntax: " snmp-mode-syntax-list nil nil)
- p) n>
- "MAX-ACCESS "
- (if tempo-interactive
- (snmp-completing-read "Max Access: " snmp-mode-access-list nil t)
- p) n>
- "STATUS "
- (if tempo-interactive
- (snmp-completing-read "Status: " snmp-mode-status-list nil t)
- p) n>
- "DESCRIPTION" n> "\"" p "\"" n>
- (P "Default Value: " defval t)
- (if (string= "" (tempo-lookup-named 'defval))
- nil
- '(l "DEFVAL { " (s defval) " }" n>))
- "::= { " (p "OID: ") " }" n)
- "objectType"
- "Insert an v2 SMI OBJECT-TYPE macro."
- 'snmpv2-tempo-tags)
- (tempo-define-template "snmpv2-table-type"
-
- '(> (P "Table Name: " table)
- (P "Entry Name: " entry t)
- (let* ((entry (tempo-lookup-named 'entry))
- (seq (copy-sequence entry)))
- (aset entry 0 (downcase (aref entry 0)))
- (aset seq 0 (upcase (aref seq 0)))
- (tempo-save-named 'obj-entry entry)
- (tempo-save-named 'seq-entry seq)
- nil)
- " OBJECT-TYPE" n>
- "SYNTAX SEQUENCE OF "
- (s seq-entry) n>
- "MAX-ACCESS not-accessible" n>
- "STATUS current" n>
- "DESCRIPTION" n> "\"" p "\"" n>
- "::= { " (p "OID: ") " }" n n>
-
- (s obj-entry) " OBJECT-TYPE" n>
- "SYNTAX " (s seq-entry) n>
- "MAX-ACCESS not-accessible" n>
- "STATUS current" n>
- "DESCRIPTION" n> "\"" p "\"" n>
- "INDEX { " (p "Index List: ") " }" n>
- "::= { " (s table) " 1 }" n n>
-
- (s seq-entry) " ::= SEQUENCE {" n> p n> "}" n)
- "tableType"
- "Insert an v2 SMI SNMP table."
- 'snmpv2-tempo-tags)
- (tempo-define-template "snmpv2-textual-convention"
- '(> (P "Textual Convention Type: ") " ::= TEXTUAL-CONVENTION" n>
- "STATUS "
- (if tempo-interactive
- (snmp-completing-read "Status: " snmp-mode-status-list nil t)
- p) n>
- "DESCRIPTION" n> "\"" p "\"" n>
- "SYNTAX "
- (if tempo-interactive
- (snmp-completing-read "Syntax: " snmp-mode-syntax-list nil nil)
- p) n> )
- "textualConvention"
- "Insert an v2 SMI TEXTUAL-CONVENTION macro."
- 'snmpv2-tempo-tags)
- (provide 'snmp-mode)
|