;; ;; nagios-mode, an Emacs mode for Nagios ;; configuration files. ;; ;; Copyright Michael Orlitzky ;; ;; http://michael.orlitzky.com/ ;; ;; This program 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 3 of the License, or ;; (at your option) any later version. ;; ;; This program 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. ;; ;; http://www.fsf.org/licensing/licenses/gpl.html ;; (require 'font-lock) (require 'regexp-opt) ;; Custom Variables (defcustom nagios-indent-level 2 "Number of spaces in one indentation (tab)." :type 'integer :group 'nagios ) ;; Indentation Voodoo (defun nagios-indent-line(&optional flag) "Indents a line, taking nesting into account." (nagios-indent-to (nagios-calculate-indent)) ) (defun nagios-indent-to(indent-column) "Indent the current line to column indent-column." (setq pos (point)) (beginning-of-line) (setq bol (point)) (setq pos-offset (- pos bol)) (setq first-char-offset (skip-chars-forward " \t")) (setq first-char-pos (+ bol first-char-offset)) (kill-region bol first-char-pos) (beginning-of-line) (setq pos-change (- indent-column first-char-offset)) (setq pos-offset (+ pos-offset pos-change)) (if (<= pos-offset indent-column) (setq pos-offset indent-column)) (while (< 0 indent-column) (insert " ") (setq indent-column (- indent-column 1))) (goto-char (+ bol pos-offset)) ) (defun nagios-in-block() "Determine if the point is inside of a {} block." (setq pos (point)) ;; Get the position of the last opening and closing braces, with ;; respect to the current point (setq last-opening-brace (re-search-backward "{" nil t)) (goto-char pos) (setq last-closing-brace (re-search-backward "}" nil t)) (goto-char pos) ;; If either is nil (not found) just set it to -1, so the comparison ;; doesn't die. (if (not last-opening-brace) (setq last-opening-brace -1)) (if (not last-closing-brace) (setq last-closing-brace -1)) ;; If the last brace seen in the buffer is an opening brace, we're ;; in a block. Otherwise, we aren't. (if (>= last-closing-brace last-opening-brace) nil t) ) (defun nagios-calculate-indent() "Calculate the level of indentation." ;; We're either inside a block, or we aren't. (setq indent 0) (if (nagios-in-block) (setq indent nagios-indent-level)) (setq pos (point)) (end-of-line) (setq eol (point)) (beginning-of-line) (setq bol (point)) ;; Set the indentation level to 0 if we find either brace on this ;; line. (if (re-search-forward "[{}]" eol t) (setq indent 0)) (goto-char pos) indent ) ;; Keymaps (defun nagios-insert-right-brace-and-indent() "Insert a '}' character, and indent the line." (interactive) (insert "}") (nagios-indent-line) ) (defvar nagios-mode-map() "Keymap used in nagios mode.") (when (not nagios-mode-map) (setq nagios-mode-map (make-sparse-keymap)) (define-key nagios-mode-map (read-kbd-macro "}") 'nagios-insert-right-brace-and-indent) ) ;; Regular Expression Transformations (defun regexp-alt-raw(element-list) "Takes a list of elements, and returns the string '\\(element1\\|element2...\\)'" ;; This is necessary since regexp-opt does not accept regular ;; expressions as arguments. We use regexp-opt when we can, of ;; course. (let ((regexp "\\(")) (mapcar (lambda(elem) (setq regexp (concat regexp "\\(" elem "\\)" "\\|"))) element-list) (concat (substring regexp 0 -2) ; Cut the last "\\|" "\\)") ) ) (defconst nagios-directives (eval-when-compile (concat "^[ \t\r\n]*" (regexp-opt '("active_checks_enabled" "address" "alias" "check_command" "check_freshness" "check_interval" "check_period" "checks_enabled" "command_line" "command_name" "contactgroups" "contact_groups" "contactgroup_members" "contact_name" "contactgroup_name" "contacts" "dependent_host_name" "dependent_service_description" "email" "event_handler" "event_handler_enabled" "execution_failure_criteria" "failure_prediction_enabled" "first_notification" "first_notification_delay" "flap_detection_enabled" "freshness_threshold" "friday" "high_flap_threshold" "host_name" "host_notification_commands" "host_notification_options" "host_notification_period" "host_notifications_enabled" "hostgroup_name" "hostgroups" "is_volatile" "last_notification" "low_flap_threshold" "max_check_attempts" "members" "monday" "normal_check_interval" "notes" "notification_failure_criteria" "notification_interval" "notification_options" "notification_period" "notifications_enabled" "obsess_over_service" "pager" "parallelize_check" "parents" "passive_checks_enabled" "process_perf_data" "retain_nonstatus_information" "retain_status_information" "retry_check_interval" "retry_interval" "saturday" "service_description" "service_notification_commands" "service_notification_options" "service_notification_period" "service_notifications_enabled" "servicegroup_name" "stalking_options" "sunday" "thursday" "timeperiod_name" "tuesday" "wednesday") t) "[ \r\n\t]+") ) ) (defconst nagios-macros (eval-when-compile (regexp-alt-raw '("\\$ADMINEMAIL\\$" "\\$ADMINPAGER\\$" "\\$ARG1\\$" "\\$ARG10\\$" "\\$ARG11\\$" "\\$ARG12\\$" "\\$ARG13\\$" "\\$ARG14\\$" "\\$ARG15\\$" "\\$ARG16\\$" "\\$ARG17\\$" "\\$ARG18\\$" "\\$ARG19\\$" "\\$ARG2\\$" "\\$ARG20\\$" "\\$ARG21\\$" "\\$ARG22\\$" "\\$ARG23\\$" "\\$ARG24\\$" "\\$ARG25\\$" "\\$ARG26\\$" "\\$ARG27\\$" "\\$ARG28\\$" "\\$ARG29\\$" "\\$ARG3\\$" "\\$ARG30\\$" "\\$ARG31\\$" "\\$ARG32\\$" "\\$ARG4\\$" "\\$ARG5\\$" "\\$ARG6\\$" "\\$ARG7\\$" "\\$ARG8\\$" "\\$ARG9\\$" "\\$COMMANDFILE\\$" "\\$CONTACTALIAS\\$" "\\$CONTACTEMAIL\\$" "\\$CONTACTGROUPALIAS\\$" "\\$CONTACTGROUPMEMBERS\\$" "\\$CONTACTGROUPNAME\\$" "\\$CONTACTGROUPNAMES\\$" "\\$CONTACTNAME\\$" "\\$CONTACTPAGER\\$" "\\$DATE\\$" "\\$EVENTSTARTTIME\\$" "\\$HOSTACKAUTHOR\\$" "\\$HOSTACKAUTHORALIAS\\$" "\\$HOSTACKAUTHORNAME\\$" "\\$HOSTACKCOMMENT\\$" "\\$HOSTACTIONURL\\$" "\\$HOSTADDRESS\\$" "\\$HOSTALIAS\\$" "\\$HOSTATTEMPT\\$" "\\$HOSTCHECKCOMMAND\\$" "\\$HOSTCHECKTYPE\\$" "\\$HOSTDISPLAYNAME\\$" "\\$HOSTDOWNTIME\\$" "\\$HOSTDURATION\\$" "\\$HOSTDURATIONSEC\\$" "\\$HOSTEVENTID\\$" "\\$HOSTEXECUTIONTIME\\$" "\\$HOSTGROUPACTIONURL\\$" "\\$HOSTGROUPALIAS\\$" "\\$HOSTGROUPMEMBERS\\$" "\\$HOSTGROUPNAME\\$" "\\$HOSTGROUPNAMES\\$" "\\$HOSTGROUPNOTES\\$" "\\$HOSTGROUPNOTESURL\\$" "\\$HOSTLATENCY\\$" "\\$HOSTNAME\\$" "\\$HOSTNOTES\\$" "\\$HOSTNOTESURL\\$" "\\$HOSTNOTIFICATIONID\\$" "\\$HOSTNOTIFICATIONNUMBER\\$" "\\$HOSTOUTPUT\\$" "\\$HOSTPERCENTCHANGE\\$" "\\$HOSTPERFDATA\\$" "\\$HOSTPERFDATAFILE\\$" "\\$HOSTPROBLEMID\\$" "\\$HOSTSTATE\\$" "\\$HOSTSTATEID\\$" "\\$HOSTSTATETYPE\\$" "\\$ISVALIDTIME\\$" "\\$LASTHOSTCHECK\\$" "\\$LASTHOSTDOWN\\$" "\\$LASTHOSTEVENTID\\$" "\\$LASTHOSTPROBLEMID\\$" "\\$LASTHOSTSTATE\\$" "\\$LASTHOSTSTATECHANGE\\$" "\\$LASTHOSTSTATEID\\$" "\\$LASTHOSTUNREACHABLE\\$" "\\$LASTHOSTUP\\$" "\\$LASTSERVICECHECK\\$" "\\$LASTSERVICECRITICAL\\$" "\\$LASTSERVICEEVENTID\\$" "\\$LASTSERVICEOK\\$" "\\$LASTSERVICEPROBLEMID\\$" "\\$LASTSERVICESTATE\\$" "\\$LASTSERVICESTATECHANGE\\$" "\\$LASTSERVICESTATEID\\$" "\\$LASTSERVICEUNKNOWN\\$" "\\$LASTSERVICEWARNING\\$" "\\$LOGFILE\\$" "\\$LONGDATETIME\\$" "\\$LONGHOSTOUTPUT\\$" "\\$LONGSERVICEOUTPUT\\$" "\\$MAINCONFIGFILE\\$" "\\$MAXHOSTATTEMPTS\\$" "\\$MAXSERVICEATTEMPTS\\$" "\\$NEXTVALIDTIME\\$" "\\$NOTIFICATIONAUTHOR\\$" "\\$NOTIFICATIONAUTHORALIAS\\$" "\\$NOTIFICATIONAUTHORNAME\\$" "\\$NOTIFICATIONCOMMENT\\$" "\\$NOTIFICATIONISESCALATED\\$" "\\$NOTIFICATIONNUMBER\\$" "\\$NOTIFICATIONRECIPIENTS\\$" "\\$NOTIFICATIONTYPE\\$" "\\$OBJECTCACHEFILE\\$" "\\$PROCESSSTARTTIME\\$" "\\$RESOURCEFILE\\$" "\\$RETENTIONDATAFILE\\$" "\\$SERVICEACKAUTHOR\\$" "\\$SERVICEACKAUTHORALIAS\\$" "\\$SERVICEACKAUTHORNAME\\$" "\\$SERVICEACKCOMMENT\\$" "\\$SERVICEACTIONURL\\$" "\\$SERVICEATTEMPT\\$" "\\$SERVICECHECKCOMMAND\\$" "\\$SERVICECHECKTYPE\\$" "\\$SERVICEDESC\\$" "\\$SERVICEDISPLAYNAME\\$" "\\$SERVICEDOWNTIME\\$" "\\$SERVICEDURATION\\$" "\\$SERVICEDURATIONSEC\\$" "\\$SERVICEEVENTID\\$" "\\$SERVICEEXECUTIONTIME\\$" "\\$SERVICEGROUPACTIONURL\\$" "\\$SERVICEGROUPALIAS\\$" "\\$SERVICEGROUPMEMBERS\\$" "\\$SERVICEGROUPNAME\\$" "\\$SERVICEGROUPNAMES\\$" "\\$SERVICEGROUPNOTES\\$" "\\$SERVICEGROUPNOTESURL\\$" "\\$SERVICEISVOLATILE\\$" "\\$SERVICELATENCY\\$" "\\$SERVICENOTES\\$" "\\$SERVICENOTESURL\\$" "\\$SERVICENOTIFICATIONID\\$" "\\$SERVICENOTIFICATIONNUMBER\\$" "\\$SERVICEOUTPUT\\$" "\\$SERVICEPERCENTCHANGE\\$" "\\$SERVICEPERFDATA\\$" "\\$SERVICEPERFDATAFILE\\$" "\\$SERVICEPROBLEMID\\$" "\\$SERVICESTATE\\$" "\\$SERVICESTATEID\\$" "\\$SERVICESTATETYPE\\$" "\\$SHORTDATETIME\\$" "\\$STATUSDATAFILE\\$" "\\$TEMPFILE\\$" "\\$TEMPPATH\\$" "\\$TIME\\$" "\\$TIMET\\$" "\\$TOTALHOSTPROBLEMS\\$" "\\$TOTALHOSTPROBLEMSUNHANDLED\\$" "\\$TOTALHOSTSDOWN\\$" "\\$TOTALHOSTSDOWNUNHANDLED\\$" "\\$TOTALHOSTSERVICES\\$" "\\$TOTALHOSTSERVICESCRITICAL\\$" "\\$TOTALHOSTSERVICESOK\\$" "\\$TOTALHOSTSERVICESUNKNOWN\\$" "\\$TOTALHOSTSERVICESWARNING\\$" "\\$TOTALHOSTSUNREACHABLE\\$" "\\$TOTALHOSTSUNREACHABLEUNHANDLED\\$" "\\$TOTALHOSTSUP\\$" "\\$TOTALSERVICEPROBLEMS\\$" "\\$TOTALSERVICEPROBLEMSUNHANDLED\\$" "\\$TOTALSERVICESCRITICAL\\$" "\\$TOTALSERVICESCRITICALUNHANDLED\\$" "\\$TOTALSERVICESOK\\$" "\\$TOTALSERVICESUNKNOWN\\$" "\\$TOTALSERVICESUNKNOWNUNHANDLED\\$" "\\$TOTALSERVICESWARNING\\$" "\\$TOTALSERVICESWARNINGUNHANDLED\\$" "\\$USER1\\$" "\\$USER10\\$" "\\$USER100\\$" "\\$USER101\\$" "\\$USER102\\$" "\\$USER103\\$" "\\$USER104\\$" "\\$USER105\\$" "\\$USER106\\$" "\\$USER107\\$" "\\$USER108\\$" "\\$USER109\\$" "\\$USER11\\$" "\\$USER110\\$" "\\$USER111\\$" "\\$USER112\\$" "\\$USER113\\$" "\\$USER114\\$" "\\$USER115\\$" "\\$USER116\\$" "\\$USER117\\$" "\\$USER118\\$" "\\$USER119\\$" "\\$USER12\\$" "\\$USER120\\$" "\\$USER121\\$" "\\$USER122\\$" "\\$USER123\\$" "\\$USER124\\$" "\\$USER125\\$" "\\$USER126\\$" "\\$USER127\\$" "\\$USER128\\$" "\\$USER129\\$" "\\$USER13\\$" "\\$USER130\\$" "\\$USER131\\$" "\\$USER132\\$" "\\$USER133\\$" "\\$USER134\\$" "\\$USER135\\$" "\\$USER136\\$" "\\$USER137\\$" "\\$USER138\\$" "\\$USER139\\$" "\\$USER14\\$" "\\$USER140\\$" "\\$USER141\\$" "\\$USER142\\$" "\\$USER143\\$" "\\$USER144\\$" "\\$USER145\\$" "\\$USER146\\$" "\\$USER147\\$" "\\$USER148\\$" "\\$USER149\\$" "\\$USER15\\$" "\\$USER150\\$" "\\$USER151\\$" "\\$USER152\\$" "\\$USER153\\$" "\\$USER154\\$" "\\$USER155\\$" "\\$USER156\\$" "\\$USER157\\$" "\\$USER158\\$" "\\$USER159\\$" "\\$USER16\\$" "\\$USER160\\$" "\\$USER161\\$" "\\$USER162\\$" "\\$USER163\\$" "\\$USER164\\$" "\\$USER165\\$" "\\$USER166\\$" "\\$USER167\\$" "\\$USER168\\$" "\\$USER169\\$" "\\$USER17\\$" "\\$USER170\\$" "\\$USER171\\$" "\\$USER172\\$" "\\$USER173\\$" "\\$USER174\\$" "\\$USER175\\$" "\\$USER176\\$" "\\$USER177\\$" "\\$USER178\\$" "\\$USER179\\$" "\\$USER18\\$" "\\$USER180\\$" "\\$USER181\\$" "\\$USER182\\$" "\\$USER183\\$" "\\$USER184\\$" "\\$USER185\\$" "\\$USER186\\$" "\\$USER187\\$" "\\$USER188\\$" "\\$USER189\\$" "\\$USER19\\$" "\\$USER190\\$" "\\$USER191\\$" "\\$USER192\\$" "\\$USER193\\$" "\\$USER194\\$" "\\$USER195\\$" "\\$USER196\\$" "\\$USER197\\$" "\\$USER198\\$" "\\$USER199\\$" "\\$USER2\\$" "\\$USER20\\$" "\\$USER200\\$" "\\$USER201\\$" "\\$USER202\\$" "\\$USER203\\$" "\\$USER204\\$" "\\$USER205\\$" "\\$USER206\\$" "\\$USER207\\$" "\\$USER208\\$" "\\$USER209\\$" "\\$USER21\\$" "\\$USER210\\$" "\\$USER211\\$" "\\$USER212\\$" "\\$USER213\\$" "\\$USER214\\$" "\\$USER215\\$" "\\$USER216\\$" "\\$USER217\\$" "\\$USER218\\$" "\\$USER219\\$" "\\$USER22\\$" "\\$USER220\\$" "\\$USER221\\$" "\\$USER222\\$" "\\$USER223\\$" "\\$USER224\\$" "\\$USER225\\$" "\\$USER226\\$" "\\$USER227\\$" "\\$USER228\\$" "\\$USER229\\$" "\\$USER23\\$" "\\$USER230\\$" "\\$USER231\\$" "\\$USER232\\$" "\\$USER233\\$" "\\$USER234\\$" "\\$USER235\\$" "\\$USER236\\$" "\\$USER237\\$" "\\$USER238\\$" "\\$USER239\\$" "\\$USER24\\$" "\\$USER240\\$" "\\$USER241\\$" "\\$USER242\\$" "\\$USER243\\$" "\\$USER244\\$" "\\$USER245\\$" "\\$USER246\\$" "\\$USER247\\$" "\\$USER248\\$" "\\$USER249\\$" "\\$USER25\\$" "\\$USER250\\$" "\\$USER251\\$" "\\$USER252\\$" "\\$USER253\\$" "\\$USER254\\$" "\\$USER255\\$" "\\$USER256\\$" "\\$USER26\\$" "\\$USER27\\$" "\\$USER28\\$" "\\$USER29\\$" "\\$USER3\\$" "\\$USER30\\$" "\\$USER31\\$" "\\$USER32\\$" "\\$USER33\\$" "\\$USER34\\$" "\\$USER35\\$" "\\$USER36\\$" "\\$USER37\\$" "\\$USER38\\$" "\\$USER39\\$" "\\$USER4\\$" "\\$USER40\\$" "\\$USER41\\$" "\\$USER42\\$" "\\$USER43\\$" "\\$USER44\\$" "\\$USER45\\$" "\\$USER46\\$" "\\$USER47\\$" "\\$USER48\\$" "\\$USER49\\$" "\\$USER5\\$" "\\$USER50\\$" "\\$USER51\\$" "\\$USER52\\$" "\\$USER53\\$" "\\$USER54\\$" "\\$USER55\\$" "\\$USER56\\$" "\\$USER57\\$" "\\$USER58\\$" "\\$USER59\\$" "\\$USER6\\$" "\\$USER60\\$" "\\$USER61\\$" "\\$USER62\\$" "\\$USER63\\$" "\\$USER64\\$" "\\$USER65\\$" "\\$USER66\\$" "\\$USER67\\$" "\\$USER68\\$" "\\$USER69\\$" "\\$USER7\\$" "\\$USER70\\$" "\\$USER71\\$" "\\$USER72\\$" "\\$USER73\\$" "\\$USER74\\$" "\\$USER75\\$" "\\$USER76\\$" "\\$USER77\\$" "\\$USER78\\$" "\\$USER79\\$" "\\$USER8\\$" "\\$USER80\\$" "\\$USER81\\$" "\\$USER82\\$" "\\$USER83\\$" "\\$USER84\\$" "\\$USER85\\$" "\\$USER86\\$" "\\$USER87\\$" "\\$USER88\\$" "\\$USER89\\$" "\\$USER9\\$" "\\$USER90\\$" "\\$USER91\\$" "\\$USER92\\$" "\\$USER93\\$" "\\$USER94\\$" "\\$USER95\\$" "\\$USER96\\$" "\\$USER97\\$" "\\$USER98\\$" "\\$USER99\\$"))) ) (defconst nagios-definitions (eval-when-compile (concat "^[ \t\r\n]*" (regexp-alt-raw '("define +\\(host\\|service\\|timeperiod\\|contact\\|command\\)" "define +\\(host\\|contact\\|service\\)group" "define +\\(service\\|host\\)dependency" "define +\\(service\\|host\\|hostgroup\\)escalation")) ;; These can be "terminated" by either an opening curly ;; brace, or a space. "\\({\\| \\)") ) ) (defconst nagios-special (eval-when-compile (concat "^[ \t\r\n]*" (regexp-opt '("name" "register" "use") t) "[ \r\n\t]+")) ) ;; The One True Font Locking Variable (defvar nagios-font-lock-keywords (list (cons nagios-special font-lock-keyword-face) (cons nagios-directives font-lock-variable-name-face) (cons nagios-macros font-lock-constant-face) (cons nagios-definitions '(1 font-lock-function-name-face))) "Rules for highlighting Nagios configuration files." ) (defvar nagios-mode-syntax-table nil "Syntax table used in nagios-mode buffers.") (if nagios-mode-syntax-table nil (setq nagios-mode-syntax-table (make-syntax-table)) (modify-syntax-entry ?# "< b" nagios-mode-syntax-table) ;; Comment style 1 (modify-syntax-entry ?\; "< b" nagios-mode-syntax-table) ;; Comment style 2 (modify-syntax-entry ?\n "> b" nagios-mode-syntax-table) ;; End comment ) ;; Main Mode Function (defun nagios-mode() "Major mode for editing Nagios configuration files." (interactive) (kill-all-local-variables) (make-local-variable 'font-lock-defaults) (make-local-variable 'comment-start) (make-local-variable 'comment-start-skip) (make-local-variable 'comment-end) (make-local-variable 'indent-line-function) (make-local-variable 'syntax-begin-function) (set-syntax-table nagios-mode-syntax-table) (setq mode-name "nagios" major-mode 'nagios-mode indent-line-function 'nagios-indent-line font-lock-defaults '(nagios-font-lock-keywords) comment-start "#" comment-start-skip "#\|; +" comment-end "" ;; Since comments and strings do not span multiple lines, ;; the syntax parser can safely start parsing at the beginning ;; of any line. syntax-begin-function 'beginning-of-line ) ;; Keyboard Mapping (use-local-map nagios-mode-map) ;; I don't /think/ I need to define this before attempting ;; to run it. Users can define it if they want. (run-hooks 'nagios-mode-hook) ) (provide 'nagios-mode)