*** empty log message ***
[ess.git] / lisp / essl-sas.el
blob12e0fb32b326d4a997c861996c08ac0b06064580
1 ;;; essl-sas.el --- SAS customization
3 ;; Copyright (C) 1997--2004 A.J. Rossini, Rich M. Heiberger, Martin
4 ;; Maechler, Kurt Hornik, Rodney Sparapani, and Stephen Eglen.
6 ;; Original Authors: Richard M. Heiberger <rmh@astro.ocis.temple.edu>,
7 ;; A.J. Rossini <rossini@u.washington.edu>,
8 ;; Rodney Sparapani <rsparap@mcw.edu>
9 ;; Created: 20 Aug 1997
10 ;; Maintainers: ESS-core <ESS-core@stat.math.ethz.ch>
12 ;; Keywords: start up, configuration.
14 ;; This file is part of ESS (Emacs Speaks Statistics).
16 ;; This file is free software; you can redistribute it and/or modify
17 ;; it under the terms of the GNU General Public License as published by
18 ;; the Free Software Foundation; either version 2, or (at your option)
19 ;; any later version.
21 ;; This file is distributed in the hope that it will be useful,
22 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
23 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 ;; GNU General Public License for more details.
26 ;; You should have received a copy of the GNU General Public License
27 ;; along with GNU Emacs; see the file COPYING. If not, write to
28 ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
30 ;;; Commentary:
31 ;;; This is based upon Version 1.4 of SAS mode:
34 ;;; sas-mode: indent, run etc, SAS programs.
35 ;;; Copyright (C) 1994--1997 Tom Cook
36 ;;; Author: Tom Cook
37 ;;; Dept. of Biostatistics
38 ;;; University of Wisconsin - Madison
39 ;;; Madison, WI 53706
40 ;;; cook@biostat.wisc.edu
41 ;;;
42 ;;; Acknowledgements:
43 ;;; Menu code for XEmacs/Lucid emacs and startup mods
44 ;;; contributed by arossini@biostats.hmc.psu.edu
45 ;;;
46 ;;; Last change: 2/1/95
47 ;;; Last change: 01/15/02
49 (ess-message "[essl-sas:] (require 'ess) ...")
50 (require 'ess)
51 (ess-message "[essl-sas:] (require 'ess-mode) ...")
52 (require 'ess-mode)
53 (require 'ess-cust)
55 (ess-message "[essl-sas:] (autoload ..) (def** ..) etc ...")
57 (autoload 'ess-transcript-mode "ess-trns" "ESS source eval mode." t)
59 (put 'ess-transcript-minor-mode 'permanent-local t)
60 (or (assq 'ess-transcript-minor-mode minor-mode-alist)
61 (setq minor-mode-alist
62 (append minor-mode-alist
63 (list '(ess-transcript-minor-mode " ESStr")))))
65 (put 'ess-listing-minor-mode 'permanent-local t)
66 (or (assq 'ess-listing-minor-mode minor-mode-alist)
67 (setq minor-mode-alist
68 (append minor-mode-alist
69 (list '(ess-listing-minor-mode " ESSlst")))))
71 (defun ess-transcript-minor-mode (&optional arg)
72 "Toggle Ess-Transcript minor mode.
73 With arg, turn Ess-Transcript minor mode on if arg is positive, off
74 otherwise. See the command `ess-transcript-mode' for more information
75 on this mode."
76 (interactive "P")
77 (setq ess-transcript-minor-mode
78 (if (null arg) (not ess-transcript-minor-mode)
79 (> (prefix-numeric-value arg) 0)))
80 (force-mode-line-update)
81 (setq mode-line-process
82 '(" [" ess-local-process-name "]")))
84 (defun ess-listing-minor-mode (&optional arg)
85 "Toggle Ess-Listing minor mode.
86 With arg, turn Ess-Listing minor mode on if arg is positive, off
87 otherwise. Ess-Listing mode is used solely to place an indicator on
88 the mode line."
89 (interactive "P")
90 (setq ess-listing-minor-mode
91 (if (null arg) (not ess-listing-minor-mode)
92 (> (prefix-numeric-value arg) 0)))
93 (force-mode-line-update)
94 (setq mode-line-process
95 '(" [" ess-local-process-name "]")))
97 (defun SAS-log-mode ()
98 "`ess-transcript-mode' for SAS."
99 (interactive)
100 (SAS-mode)
101 (ess-transcript-minor-mode 1)
102 (toggle-read-only t)) ;; to protect the buffer.
104 (defun SAS-listing-mode()
105 "Fundamental mode with `ess-listing-minor-mode' and read-only."
106 (interactive)
107 (fundamental-mode)
108 (ess-listing-minor-mode t)
109 (use-local-map sas-mode-local-map)
110 (toggle-read-only t)) ;; to protect the buffer.
112 (if (not (featurep 'xemacs))
113 (setq auto-mode-alist
114 (append '(("\\.[lL][sS][tT]\\'" . sas-listing-mode)) auto-mode-alist)))
115 ;;;###autoload(add-to-list 'auto-mode-alist '("\\.[lL][sS][tT]\\'" . sas-listing-mode))
117 (fset 'sas-log-mode 'SAS-log-mode)
118 (fset 'SAS-transcript-mode 'SAS-log-mode)
119 (fset 'sas-transcript-mode 'SAS-log-mode)
120 (fset 'sas-mode 'SAS-mode)
121 (fset 'sas-listing-mode 'SAS-listing-mode)
123 (defcustom sas-indent-width 4
124 "*Amount to indent sas statements."
125 :group 'ess-sas
126 :type 'integer)
128 (defcustom sas-indent-ignore-comment "*"
129 "*Comments that start with this string are ignored in indentation."
130 :group 'ess-sas
131 :type 'string)
133 (defcustom sas-require-confirmation t
134 "*Require confirmation when revisiting a modified sas-output file."
135 :group 'ess-sas
136 :type 'boolean)
138 ;; user can specify the sas program name
139 (defcustom sas-program
140 (if (equal system-type 'Apple-Macintosh) "invoke SAS using program file" "sas")
141 "*Command to invoke SAS, default for buffer-local `ess-sas-submit-command'."
142 :group 'ess-sas
143 :type 'string)
145 (defcustom sas-pre-run-hook nil
146 "Hook to execute prior to running SAS via `submit-sas'."
147 :group 'ess-sas
148 :type 'hook)
150 ;never used--see ess-sas-submit-command-options in essa-sas.el
151 ;(defcustom sas-options-string ""
152 ; "*Options to be passed to sas as if typed on the command line."
153 ; :group 'ess-sas
154 ; :type 'string)
156 (defcustom sas-notify t
157 "*Beep and display message when job is done."
158 :group 'ess-sas
159 :type 'boolean)
161 (defcustom sas-error-notify t
162 "*If `sas-notify' t, indicate errors in log file upon completion."
163 :group 'ess-sas
164 :type 'boolean)
166 (defcustom sas-get-options nil
167 "Options to be passed to SAS in sas-get-dataset."
168 :group 'ess-sas
169 :type '(choice (const nil) string))
171 (defcustom sas-get-options-history nil
172 "History list of Options passed to SAS in sas-get-dataset."
173 :group 'ess-sas)
175 (defcustom sas-page-number-max-line 3
176 "*Number of lines from the page break, to search for the page
177 number."
178 :group 'ess-sas
179 :type 'integer)
181 (defcustom sas-notify-popup nil
182 "*If this and sas-notify are t), popup a window when SAS job ends."
183 :group 'ess-sas
184 :type 'boolean)
186 (defcustom sas-tmp-libname "_tmp_"
187 "*Libname to use for sas-get-dataset."
188 :group 'ess-sas
189 :type 'string)
191 (defcustom sas-file-name nil
192 "*The name of the current sas file."
193 :group 'ess-sas
194 :type '(choice (const nil) file))
196 ;; The next two are ``the inside of [...] in a regexp'' to be used in
197 ;; (skip-chars-(for|back)ward SAS-..-chars)
198 (defcustom sas-white-chars " \t\n\f"
199 "This does NOT escape blanks (RMH, 2000/03/20)."
200 :group 'ess-sas
201 :type 'string)
203 (defcustom sas-comment-chars (concat sas-white-chars ";")
204 "Doc?"
205 :group 'ess-sas
206 :type 'string)
208 (defcustom ess-sas-run-make-regexp nil
209 "If you do not want to run make-regexp, then set to nil."
210 :group 'ess-sas
211 :type '(choice (const nil) string))
213 (require 'essa-sas)
215 (defvar sas-buffer-name nil)
216 (defvar sas-file-root nil)
217 (defvar sas-submitable nil)
218 (defvar sas-dataset nil)
219 (defvar SAS-syntax-table nil "Syntax table for SAS code.")
221 (if SAS-syntax-table nil
222 (setq SAS-syntax-table (make-syntax-table))
224 ;; (if (equal system-type 'windows-nt)
225 ;; ;; backslash is punctuation (used in MS file names)
226 ;; (modify-syntax-entry ?\\ "." SAS-syntax-table)
227 ;; ;; backslash is an escape character
228 ;; (modify-syntax-entry ?\\ "\\" SAS-syntax-table))
229 (modify-syntax-entry ?\\ "." SAS-syntax-table) ;; backslash is punctuation
230 (modify-syntax-entry ?+ "." SAS-syntax-table)
231 (modify-syntax-entry ?- "." SAS-syntax-table)
232 (modify-syntax-entry ?= "." SAS-syntax-table)
233 (modify-syntax-entry ?% "w" SAS-syntax-table)
234 (modify-syntax-entry ?< "." SAS-syntax-table)
235 (modify-syntax-entry ?> "." SAS-syntax-table)
236 (modify-syntax-entry ?& "w" SAS-syntax-table)
237 (modify-syntax-entry ?| "." SAS-syntax-table)
238 (modify-syntax-entry ?\' "\"" SAS-syntax-table)
239 (modify-syntax-entry ?* ". 23" SAS-syntax-table) ; comment character
240 (modify-syntax-entry ?\; "." SAS-syntax-table)
241 (modify-syntax-entry ?_ "w" SAS-syntax-table)
242 (modify-syntax-entry ?< "." SAS-syntax-table)
243 (modify-syntax-entry ?> "." SAS-syntax-table)
244 (modify-syntax-entry ?/ ". 14" SAS-syntax-table) ; comment character
245 (modify-syntax-entry ?. "w" SAS-syntax-table))
247 (if (or window-system
248 noninteractive) ; compilation!
249 (progn
250 (require 'font-lock)
252 (defvar SAS-mode-font-lock-keywords
253 (if ess-sas-run-make-regexp
254 (list
255 ;; SAS comments
256 (cons "^[ \t]*%?\\*.*;" font-lock-comment-face)
257 (cons ";[ \t]*%?\\*.*;" font-lock-comment-face)
258 (list "/\\*\\([^*/]\\)*\\*/" 0 font-lock-comment-face t)
260 ;; SAS execution blocks, DATA/RUN, PROC/RUN, %MACRO/%MEND
261 (cons "\\<\\(data\\|run\\|%macro\\|%mend\\)\\>" font-lock-reference-face)
262 (cons "\\<proc[ \t]+[a-z][a-z_0-9]+" font-lock-reference-face)
264 ;; SAS statements
266 (cons (concat
267 "\\<"
268 "%?do[ \t]*" (make-regexp '("over" "%?until" "%?while") t) "?"
269 "\\>")
270 font-lock-keyword-face)
272 (cons (concat
273 "\\<"
274 (make-regexp
276 "abort" "array" "attrib" "by" "delete" "display" "dm"
277 "drop" "error" "file" "filename" "footnote\\(10?\\|[2-9]\\)?"
278 "format"
279 "%go[ \t]*to" "%if" "%then" "%else"
280 "go[ \t]*to" "if" "then" "else"
281 "infile" "informat" "input" "%input" "keep" "label"
282 "length" "libname" "link"
283 "merge" "missing" "modify" "note" "options" "goptions" "output"
284 "otherwise" "put" "%put" "rename" "retain" "select" "when" "set"
285 "skip" "title\\(10?\\|[2-9]\\)?" "where" "window" "update" "out"
286 "change" "class" "exchange" "exclude" "freq" "id" "index"
287 "model" "plot" "save" "sum" "tables?" "var" "weight" "with"
288 "manova" "repeated" "value" "random" "means" "lsmeans"
289 ;; SAS macro statements not handled above
290 "%global" "%include" "%local" "%let" "%sysexec"
291 ) t) "\\>")
292 font-lock-keyword-face)
294 ;; SAS statements that must be followed by a semi-colon
295 (cons (concat
296 "\\<"
297 (make-regexp
299 "cards4?" "end" "%end" "endsas" "list" "lostcard" "page"
300 "return" "stop"
301 ) t) "\\>" "[ \t]*;")
302 font-lock-keyword-face)
304 ;; SAS/GRAPH statements not handled above
305 (cons (concat
306 "\\<"
307 (make-regexp
308 '("axis" "legend" "pattern" "symbol") t) "\\([1-9][0-9]?\\)?"
309 "\\>")
310 font-lock-keyword-face)
312 ;; SAS functions and SAS macro functions
313 (cons "%[a-z_][a-z_0-9]*[ \t]*[(;]"
314 font-lock-function-name-face)
315 (cons "\\<call[ \t]+[a-z_][a-z_0-9]*[ \t]*("
316 font-lock-function-name-face)
318 (cons (concat
319 "\\<"
320 (make-regexp
322 "abs" "arcos" "arsin" "atan" "betainv" "byte" "ceil" "cinv"
323 "collate" "compress" "cosh?" "css" "cv"
324 "daccdb" "daccdbsl" "daccsl" "daccsyd" "dacctab"
325 "depdb" "depdbsl" "depsl" "depsyd" "deptab"
326 "date" "datejul" "datepart" "datetime" "day" "hms" "dhms" "dif"
327 "digamma" "dim" "erfc?" "exp" "finv"
328 "fipnamel?" "fipstate" "floor" "fuzz" "gaminv" "gamma"
329 "hbound" "hour" "indexc?" "input" "int" "intck" "intnx" "intrr"
330 "irr" "juldate" "kurtosis" "lag" "lbound" "left" "length"
331 "lgamma" "log" "log10" "log2" "max" "mdy" "mean" "min" "minute"
332 "mod" "month" "mort" "n" "netpv" "nmiss" "normal" "npv"
333 ;;;) t) "\\>" "[ \t]*(")
334 ;;; font-lock-function-name-face)
336 ;;; (cons (concat "\\<"
337 ;;;(make-regexp '(
338 "probbeta" "probbnml" "probchi" "probf" "probgam" "probhypr"
339 "probit" "probnegb" "probnorm" "probt"
340 "ordinal" "poisson" "put" "qtr" "range" "rank" "repeat"
341 "ranbin" "rancau" "ranexp" "rangam" "rannor" "ranpoi"
342 "rantbl" "rantri" "ranuni"
343 "reverse" "right" "round" "saving" "scan" "second" "sign" "sinh?"
344 "sqrt" "std" "stderr" "stfips" "stnamel?" "substr" "sum"
345 "symget" "tanh?" "time" "timepart" "tinv" "today" "translate"
346 "trigamma" "trim" "trunc" "uniform" "upcase" "uss" "var"
347 "verify" "weekday" "year" "yyq"
348 "zipfips" "zipnamel?" "zipstate"
349 ;;;) t) "\\>" "[ \t]*(")
350 ;;; font-lock-function-name-face)
353 ;;; ;; SAS functions introduced in Technical Report P-222
354 ;;; ;; SCL functions that are known to work with SAS macro function %sysfunc
355 ;;; (cons (concat "\\<"
356 ;;;(make-regexp '(
357 "airy" "band" "blshift" "brshift" "bnot" "bor" "bxor"
358 "cnonct" "fnonct" "tnonct" "compbl" "dairy" "dequote"
359 "ibessel" "jbessel"
360 "indexw" "inputc" "inputn" "lowcase"
361 "putc" "putn" "quote" "resolve" "soundex" "sysprod"
362 "tranwrd" "trimn"
363 "%sysfunc" "attrc" "attrn" "cexist" "close" "dclose" "dnum"
364 "dopen" "dread" "exist" "fclose" "fetchobs" "fileexist"
365 "finfo" "fopen" "fput" "fwrite" "getoption"
366 "getvarc" "getvarn" "libname" "libref" "open" "optgetn" "optsetn"
367 "pathname" "sysmsg" "varfmt" "varlabel" "varnum" "vartype"
368 ) t) "\\>" "[ \t]*(")
369 font-lock-function-name-face)
371 (list
372 ;; .log NOTE: messages
373 (cons "^NOTE: .*$" font-lock-reference-face)
375 ;; .log ERROR: messages
376 (cons "^ERROR: .*$" font-lock-keyword-face)
378 ;; .log WARNING: messages
379 (cons "^WARNING: .*$" font-lock-function-name-face)
381 ;; SAS comments
382 ;; /* */ handled by grammar above
383 ;; (list "/\\*.*\\*/" 0 font-lock-comment-face t)
384 (cons "\\(^[0-9]*\\|;\\)[ \t]*\\(%?\\*\\|comment\\).*\\(;\\|$\\)" font-lock-comment-face)
386 ;; SAS execution blocks, DATA/RUN, PROC/RUN, SAS Macro Statements
387 (cons "\\<%do[ \t]*\\(%until\\|%while\\)?\\>"
388 font-lock-reference-face)
389 ;;(cons (concat "\\(^[0-9]*\\|;\\)[ \t]*"
390 ;;"%\\(end\\|global\\|local\\|m\\(acro\\|end\\)\\)"
391 ;;"\\>") font-lock-reference-face)
392 (cons "\\<%\\(end\\|global\\|local\\|m\\(acro\\|end\\)\\)\\>"
393 font-lock-reference-face)
395 (cons (concat "\\(^[0-9]*\\|;\\|):\\|%then\\|%else\\)[ \t]*"
396 "\\(data\\|endsas\\|finish\\|quit\\|run\\|start\\)[ \t\n;]")
397 font-lock-reference-face)
398 (cons (concat "\\(^[0-9]*\\|;\\|):\\|%then\\|%else\\)[ \t]*"
399 "proc[ \t]+[a-z][a-z_0-9]+") font-lock-reference-face)
401 ;;(cons (concat "\\(^[0-9]*\\|;\\|%then\\|%else\\)[ \t]*"
402 ;;"\\(%\\(go[ \t]*to\\|i\\(f\\|n\\(clude\\|put\\)\\)\\|let\\|put\\|sysexec\\)\\)"
403 ;;"\\>") font-lock-reference-face)
404 (cons "\\<%\\(go[ \t]*to\\|i\\(f\\|n\\(clude\\|put\\)\\)\\|let\\|put\\|sysexec\\)\\>"
405 font-lock-reference-face)
407 (cons "\\<%\\(by\\|else\\|t\\(o\\|hen\\)\\)\\>"
408 font-lock-reference-face)
410 ;; SAS dataset options/PROC statements followed by an equal sign/left parentheses
412 (cons (concat
413 "[ \t(,]"
414 "\\(attrib\\|by\\|compress\\|d\\(ata\\|rop\\)\\|f\\(irstobs\\|ormat\\)"
415 "\\|i\\(d\\|f\\|n\\)\\|ke\\(ep\\|y\\)\\|l\\(abel\\|ength\\)"
416 "\\|o\\(bs\\|rder\\|ut\\)\\|rename\\|s\\(ortedby\\|plit\\)"
417 "\\|var\\|where\\)"
418 "[ \t]*=")
419 font-lock-keyword-face)
420 (cons "\\<\\(in\\(:\\|dex[ \t]*=\\)?\\|until\\|wh\\(en\\|ile\\)\\)[ \t]*("
421 font-lock-keyword-face)
423 ;; SAS statements
424 (cons (concat
425 "\\(^[0-9]*\\|):\\|[;,]\\|then\\|else\\)[ \t]*"
426 "\\(a\\(bort\\|rray\\|ttrib\\)\\|by"
427 "\\|c\\(hange\\|lass\\|ontrast\\)"
428 "\\|d\\(elete\\|isplay\\|m\\|o\\([ \t]+\\(data\\|over\\)\\)?\\|rop\\)"
429 "\\|e\\(rror\\|stimate\\|xc\\(hange\\|lude\\)\\)"
430 "\\|f\\(ile\\(name\\)?\\|o\\(otnote\\(10?\\|[2-9]\\)?\\|rmat\\)\\|req\\)"
431 "\\|go\\([ \t]*to\\|ptions\\)"
432 "\\|i\\(d\\|f\\|n\\(dex\\|f\\(ile\\|ormat\\)\\|put\\|value\\)\\)"
433 "\\|keep\\|l\\(abel\\|ength\\|i\\(bname\\|nk\\|st\\)\\|smeans\\)"
434 "\\|m\\(anova\\|e\\(ans\\|rge\\)\\|issing\\|od\\(el\\|ify\\)\\)\\|note"
435 "\\|o\\(ptions\\|therwise\\|utput\\)\\|p\\(lot\\|ut\\)"
436 "\\|r\\(andom\\|e\\(name\\|peated\\|tain\\)\\)"
437 "\\|s\\(ave\\|e\\(lect\\|t\\)\\|kip\\|trata\\|umby\\)"
438 "\\|t\\(ables?\\|i\\(me\\|tle\\(10?\\|[2-9]\\)?\\)\\)\\|update"
439 "\\|va\\(lue\\|r\\)\\|w\\(eight\\|here\\|i\\(ndow\\|th\\)\\)"
441 ;; IML statements that are not also SAS statements
442 "\\|append\\|c\\(lose\\(file\\)?\\|reate\\)\\|edit\\|f\\(ind\\|orce\\|ree\\)"
443 "\\|insert\\|load\\|mattrib\\|p\\(a[ru]se\\|rint\\|urge\\)"
444 "\\|re\\(move\\|peat\\|place\\|set\\|sume\\)"
445 "\\|s\\(et\\(in\\|out\\)\\|how\\|ort\\|tore\\|ummary\\)\\|use\\)?"
447 "\\>") font-lock-keyword-face)
451 ;; (cons "\\<\\(\\(then\\|else\\)[ \t]*\\)?\\(do\\([ \t]*over\\)?\\|else\\)\\>"
452 ;; font-lock-keyword-face)
454 ;; SAS statements that must be followed by a semi-colon
455 (cons (concat
456 "\\(^[0-9]*\\|):\\|[;,]\\|then\\|else\\)[ \t]*"
457 "\\(cards4?\\|datalines\\|end\\|l\\(ostcard\\)\\|page\\|return\\|stop\\)?"
458 "[ \t]*;") font-lock-keyword-face)
460 ;; SAS/GRAPH statements not handled above
461 (cons (concat
462 "\\(^[0-9]*\\|):\\|[;,]\\)[ \t]*"
463 "\\(axis\\|legend\\|pattern\\|symbol\\)"
464 "\\([1-9][0-9]?\\)?\\>") font-lock-keyword-face)
466 ;; SAS Datastep functions and SAS macro functions
467 ;(cons "%[a-z_][a-z_0-9]*[ \t]*[(;]"
468 ;; SAS macro functions occasionally defined with no arguments
469 (cons "%[a-z_][a-z_0-9]*[ \t();]"
470 font-lock-function-name-face)
471 (cons "\\<call[ \t]+[a-z_][a-z_0-9]*[ \t]*("
472 font-lock-function-name-face)
474 (cons (concat
475 "\\<"
476 "\\(a\\(bs\\|r\\(cos\\|sin\\)\\|tan\\)\\|b\\(etainv\\|yte\\)"
477 "\\|c\\(eil\\|inv\\|o\\(llate\\|mpress\\|sh?\\)\\|ss\\|v\\)"
478 "\\|dacc\\(db\\(\\|sl\\)\\|s\\(l\\|yd\\)\\|tab\\)"
479 "\\|dep\\(db\\(\\|sl\\)\\|s\\(l\\|yd\\)\\|tab\\)"
480 "\\|d\\(a\\(te\\(\\|jul\\|part\\|time\\)\\|y\\)\\|hms\\|i\\([fm]\\|gamma\\)\\)"
481 "\\|e\\(rfc?\\|xp\\)"
482 "\\|f\\(i\\(nv\\|p\\(namel?\\|state\\)\\)\\|loor\\|uzz\\)\\|gam\\(inv\\|ma\\)"
483 "\\|h\\(bound\\|ms\\|our\\)\\|i\\(n\\(dexc?\\|put\\|t\\(\\|ck\\|nx\\|rr\\)\\)\\|rr\\)"
484 "\\|juldate\\|kurtosis\\|l\\(ag\\|bound\\|e\\(ft\\|ngth\\)\\|gamma\\|og\\(\\|10\\|2\\)\\)"
485 "\\|m\\(ax\\|dy\\|ean\\|in\\(\\|ute\\)\\|o\\(d\\|nth\\|rt\\)\\)\\|n\\(\\|etpv\\|miss\\|ormal\\|pv\\)"
486 "\\|prob\\([ft]\\|b\\(eta\\|nml\\)\\|chi\\|gam\\|hypr\\|it\\|n\\(egb\\|orm\\)\\)"
487 "\\|ordinal\\|p\\(oisson\\|ut\\)\\|qtr\\|r\\(e\\(peat\\|verse\\)\\|ight\\|ound\\)"
488 "\\|ran\\(bin\\|cau\\|exp\\|g\\(am\\|e\\)\\|k\\|nor\\|poi\\|t\\(bl\\|ri\\)\\|uni\\)"
489 "\\|s\\(aving\\|can\\|econd\\|i\\(gn\\|nh?\\)\\|qrt\\|t\\(d\\(\\|err\\)\\|fips\\|namel?\\)\\|u\\(bstr\\|m\\)\\|ymget\\)"
490 "\\|t\\(anh?\\|i\\(me\\(\\|part\\)\\|nv\\)\\|oday\\|r\\(anslate\\|i\\(gamma\\|m\\)\\|unc\\)\\)"
491 "\\|u\\(niform\\|pcase\\|ss\\)\\|v\\(ar\\|erify\\)"
492 "\\|weekday\\|y\\(ear\\|yq\\)\\|zip\\(fips\\|namel?\\|state\\)"
494 ;;; ;; SAS functions introduced in Technical Report P-222
496 "\\|airy\\|b\\(and\\|lshift\\|not\\|or\\|rshift\\|xor\\)"
497 "\\|c\\(nonct\\|ompbl\\)\\|d\\(airy\\|equote\\)\\|fnonct\\|tnonct"
498 "\\|i\\(bessel\\|n\\(dexw\\|put[cn]\\)\\)\\|jbessel\\|put[cn]"
499 "\\|lowcase\\|quote\\|resolve\\|s\\(oundex\\|ysprod\\)\\|tr\\(anwrd\\|imn\\)"
501 ;;; ;; IML functions that are not also Datastep functions
502 "\\|a\\(ll\\|ny\\|pply\\|rmasim\\)\\|b\\(lock\\|ranks\\|tran\\)"
503 "\\|c\\(har\\|hoose\\|on\\(cat\\|tents\\|vexit\\|vmod\\)\\|ovlag\\|shape\\|usum\\|vexhull\\)"
504 "\\|d\\(atasets\\|esignf?\\|et\\|iag\\|o\\|uration\\)"
505 "\\|e\\(chelon\\|igv\\(al\\|ec\\)\\)\\|f\\(ft\\|orward\\)\\|ginv"
506 "\\|h\\(alf\\|ankel\\|dir\\|ermite\\|omogen\\)"
507 "\\|i\\(\\|fft\\|nsert\\|nv\\(updt\\)?\\)\\|j\\(\\|root\\)\\|loc\\|mad"
508 "\\|n\\(ame\\|col\\|leng\\|row\\|um\\)\\|o\\(pscal\\|rpol\\)"
509 "\\|p\\(olyroot\\|roduct\\|v\\)\\|r\\(anktie\\|ates\\|atio\\|emove\\|eturn\\|oot\\|owcatc?\\)"
510 "\\|s\\(etdif\\|hape\\|olve\\|plinev\\|pot\\|qrsym\\|ssq\\|torage\\|weep\\|ymsqr\\)"
511 "\\|t\\(\\|eigv\\(al\\|ec\\)\\|oeplitz\\|race\\|risolv\\|ype\\)"
512 "\\|uni\\(on\\|que\\)\\|v\\(alue\\|ecdiag\\)\\|x\\(mult\\|sect\\)\\|yield"
514 ;;; ;; SCL functions that are known to work with SAS macro function %sysfunc
516 "\\|attr[cn]\\|c\\(exist\\|lose\\)\\|d\\(close\\|num\\|open\\|read\\)"
517 "\\|exist\\|f\\(close\\|etchobs\\|i\\(leexist\\|nfo\\)\\|open\\|put\\|write\\)"
518 "\\|get\\(option\\|var[cn]\\)\\|lib\\(name\\|ref\\)\\|op\\(en\\|t\\(getn\\|setn\\)\\)"
519 "\\|pathname\\|sysmsg\\|var\\(fmt\\|l\\(abel\\|en\\)\\|n\\(ame\\|um\\)\\|type\\)\\)"
520 "[ \t]*(") font-lock-function-name-face)
522 "Font Lock regexs for SAS.")
524 (defvar SAS-mode-font-lock-keywords "") ;; empty if not window-system
525 ); only if window-system
527 (defvar SAS-editing-alist
528 '((sentence-end . ";[\t\n */]*")
529 (paragraph-start . "^[ \t]*$")
530 (paragraph-separate . "^[ \t]*$")
531 (paragraph-ignore-fill-prefix . t)
532 ;;(fill-paragraph-function . 'lisp-fill-paragraph)
533 (adaptive-fill-mode . nil)
534 (indent-line-function . 'sas-indent-line)
535 ;;(indent-region-function . 'sas-indent-region)
536 (require-final-newline . t)
537 (comment-start . "\\*\\|/\\*")
538 (comment-start-skip . "\\*+")
539 (comment-end . ";\\|\\*/")
540 (comment-column . 40)
541 ;;(comment-indent-function . 'lisp-comment-indent)
542 (parse-sexp-ignore-comments . t)
543 (ess-set-style . ess-default-style)
544 (ess-local-process-name . nil)
545 ;;(ess-keep-dump-files . 'ask)
546 (tab-stop-list . ess-sas-tab-stop-alist)
547 (ess-mode-syntax-table . SAS-syntax-table)
548 (font-lock-keywords-case-fold-search . t)
549 (font-lock-defaults . '(SAS-mode-font-lock-keywords)))
550 "General options for editing SAS source files.")
552 (defun beginning-of-sas-statement (arg &optional comment-start)
553 "Move point to beginning of current sas statement."
554 (interactive "P")
555 (let ((pos (point))
557 (if (search-forward ";" nil 1) (forward-char -1))
558 (re-search-backward ";[ \n*/]*$" (point-min) 1 arg)
559 (skip-chars-forward sas-comment-chars)
560 (if comment-start nil
561 (if (looking-at "\\*/")
562 (progn (forward-char 2)
563 (skip-chars-forward sas-comment-chars)))
564 (while (looking-at "/\\*")
565 (if (not (search-forward "*/" pos t 1)) ;;(;; (point-max) 1 1)
566 (forward-char 2))
567 (skip-chars-forward sas-white-chars)))))
569 (defun sas-indent-line ()
570 "Indent function for SAS mode."
571 (interactive)
572 (let (indent prev-end
573 (pos (- (point-max) (point)))
574 (case-fold-search t)
575 (cur-ind (current-indentation))
576 (comment-col (sas-comment-start-col))) ;; 2/1/95 TDC
577 (save-excursion
578 (cond ((progn
579 (back-to-indentation)
580 (or (bobp)
581 (looking-at
582 "data[ ;]\\|proc[ ;]\\|run[ ;]\\|endsas[ ;]\\|g?options[ ;]\\|%macro[ ;]\\|%mend[ ;]")))
583 ;; Case where current statement is DATA, PROC, etc...
584 (setq prev-end (point))
585 (goto-char (point-min))
586 ;; Added 6/27/94
587 ;; May get fooled if %MACRO, %DO, etc embedded in comments
588 (setq indent
589 (+ (* (- (sas-how-many "^[ \t]*%macro\\|[ \t]+%do"
590 prev-end)
591 (sas-how-many "^[ \t]*%mend\\|%end" prev-end))
592 sas-indent-width) comment-col))) ;; 2/1/95 TDC
593 ;; Case where current line begins with sas-indent-ignore-comment
594 ;; added 6/27/94 to leave "* ;" comments alone.
595 ((progn
596 (back-to-indentation)
597 (and (not (looking-at "*/"))
598 (looking-at (concat sas-indent-ignore-comment "\\|/\\*"))))
599 (setq indent (current-indentation)))
600 ;; Case where current statement not DATA, PROC etc...
601 (t (beginning-of-line 1)
602 (skip-chars-backward sas-white-chars)
603 (if (bobp) nil
604 (backward-char 1))
605 (cond
606 ((looking-at ";") ; modified 1/31/95
607 (setq indent (sas-next-statement-indentation)))
608 ((save-excursion;; added 4/28/94 to properly check
609 (if (bobp) () (backward-char 1));; for end of comment
610 (setq prev-end (point))
611 (looking-at "*/"));; improved 1/31/95
612 (save-excursion
613 (search-backward "*/"
614 (point-min) 1 1); comment start is first /*
615 (search-forward "/*"
616 prev-end 1 1) ; after previous */
617 (backward-char 2) ; 2/1/95 TDC
618 (skip-chars-backward sas-white-chars)
619 (setq indent
620 (if (bobp) 0
621 (if (looking-at ";")
622 (sas-next-statement-indentation)
623 (+ (current-indentation) sas-indent-width))))))
625 ;; added 6/27/94 to leave "* ;" comments alone
626 ((save-excursion
627 (progn
628 (beginning-of-sas-statement 1 t)
629 (and (not (looking-at "*/"))
630 (looking-at sas-indent-ignore-comment))))
631 (setq indent cur-ind))
632 ((progn
633 (beginning-of-sas-statement 1)
634 (bobp));; added 4/13/94
635 (setq indent sas-indent-width));; so the first line works
637 (if (progn
638 (save-excursion
639 (beginning-of-line 1)
640 (skip-chars-backward sas-white-chars)
641 (if (bobp) nil (backward-char 1))
642 (or (looking-at ";")
643 (bobp) (backward-char 1) (looking-at "\\*/"))))
644 (setq indent (+ (current-indentation) sas-indent-width))
645 (setq indent (current-indentation))))))))
646 (save-excursion
647 (let (beg end)
648 (back-to-indentation)
649 (setq end (point))
650 (beginning-of-line 1)
651 (setq beg (point))
652 (delete-region beg end)
653 (indent-to indent)))
654 (if (> (- (point-max) pos) (point))
655 (goto-char (- (point-max) pos)))))
658 ;;(defun sas-indent-region (start end)
659 ;; "Indent a region of SAS code."
660 ;; (interactive "r")
661 ;; (save-excursion
662 ;; (let ((endmark (copy-marker end)))
663 ;; (goto-char start)
664 ;; (and (bolp) (not (eolp))
665 ;; (sas-indent-line))
666 ;; (indent-sexp endmark)
667 ;; (set-marker endmark nil))))
670 (defun indent-sas-statement (arg)
671 "Indent all continuation lines sas-indent-width spaces from first
672 line of statement."
673 (interactive "p")
674 (let (end)
675 (save-excursion
676 (if (> arg 0)
677 (while (and (> arg 0) (search-forward ";" (point-max) 1 1))
678 (setq end (point))
679 (if (bobp) nil (backward-char 1))
680 (beginning-of-sas-statement 1)
681 (forward-char 1)
682 (indent-region (point)
684 (+ (current-column) (1- sas-indent-width)))
685 (search-forward ";" (point-max) 1 1)
686 (setq arg (1- arg)))))))
688 ;; added 9/31/94
689 (defun sas-next-statement-indentation ()
690 "Returns the correct indentation of the next sas statement.
691 The current version assumes that point is at the end of the statement.
692 This will (hopefully) be fixed in later versions."
693 (if (bobp) 0
694 (save-excursion
695 (let ((prev-end (point)))
696 (beginning-of-sas-statement 1)
697 (while (and (not (bobp))
698 (not (looking-at "*/"))
699 (looking-at sas-indent-ignore-comment))
700 (skip-chars-backward sas-white-chars)
701 (if (bobp) nil
702 (backward-char 1))
703 (setq prev-end (point))
704 (beginning-of-sas-statement 1 t))
705 (if (or
706 (looking-at
707 "data[ \n\t;]\\|proc[ \n\t]\\|%?do[ \n\t;]\\|%macro[ \n\t]\\|/\\*")
708 (save-excursion
709 (re-search-forward
710 "\\b%?then\\>[ \n\t]*\\b%?do\\>\\|\\b%?else\\>[ \n\t]*\\b%?do\\>"
711 prev-end 1 1))) ; fixed 1/30/95 to avoid being fooled by
712 ; variable names starting with "do"
713 (+ (current-indentation) sas-indent-width)
714 (if (looking-at "%?end[ ;\n]\\|%mend[ ;\n]\\|\\*/")
715 (max (- (current-indentation) sas-indent-width) 0)
716 (current-indentation)))))))
718 ;; added 2/1/95
719 (defun sas-comment-start-col ()
720 "If the current line is inside a /* */ comment, returns column in which the
721 opening /* appears. returns 0 otherwise."
722 (let ((pos (point)))
723 (save-excursion
724 (if (and (search-backward "*/" (point-min) 1 1)
725 (search-forward "/*" pos 1 1))
726 (current-indentation)
727 0))))
730 ;; Created 6/27/94 to verify that RUN; statements match PROC and DATA
731 ;; statements. Useful since indentation my be goofy w/o "RUN;"
732 (defun sas-check-run-statements ()
733 "Check to see that \"run\" statements are matched with proc, data statements."
734 (interactive)
735 (let (pos
736 (ok t)
737 (eob-ok t))
738 (save-excursion
739 (beginning-of-line)
740 (while ok
741 (if (re-search-forward
742 "\\(^[ \t]*run[ ;]\\)\\|\\(^[ \t]*proc \\|^[ \t]*data[ ;]\\)"
743 nil 1)
744 (if (match-beginning 2)
745 (if (re-search-forward
746 "\\(^[ \t]*run[ ;]\\)\\|\\(^[ \t]*proc \\|^[ \t]*data[ ;]\\)"
747 nil t)
748 (progn (setq pos (point))
749 (setq ok (match-beginning 1)))
750 (setq eob-ok nil pos (point-max))))
751 (setq ok nil)))
752 (setq ok (eobp)))
753 (if (and ok eob-ok) (message "Run statements match")
754 (goto-char pos)
755 (beep)
756 (message "Missing Run Statement."))))
759 (defun sas-fix-life-tables (start end)
760 "Remove censored and duplicate observations from life tables generated by
761 Proc Lifetest. Operates on current region. A major space saver if there is
762 heavy censoring."
763 (interactive "r")
764 (save-excursion
765 (shell-command-on-region
766 start end
767 "sed \"\\? *\\. *\\. *\\. ?d\"" t)))
768 ;;(vip-goto-line 1)
769 ;;(setq ex-g-flag nil
770 ;;ex-g-variant nil)
771 ;;(vip-ex "1,$g/ \\. \\. \\. /d")))
773 (defun sas-fix-page-numbers (offset &optional page-num)
774 "Fix number of current page in sas output files after editing. Add
775 OFFSET to actual page number."
776 (interactive "P")
777 (if (not offset) (setq offset 0))
778 (if (not page-num) (setq page-num (sas-page-number)))
779 (save-excursion
780 (if (/= (preceding-char) ?\C-l) (backward-page 1))
781 (let (end len mstart mend)
782 (save-excursion
783 (forward-line sas-page-number-max-line)
784 (setq end (point)))
785 (if (re-search-forward
786 "\\(^[0-9]+[ ]\\)\\|\\([ ][0-9]+$\\)"
787 end t)
788 (progn (setq len (- (match-end 0) (match-beginning 0))
789 mstart (match-beginning 0)
790 mend (match-end 0))
791 (delete-region mstart mend)
792 (if (eolp)
793 (insert (format
794 (concat "%" len "d") (+ page-num offset)))
795 (insert (substring
796 (concat (+ (sas-page-number) offset) " ")
797 0 len))))))))
799 (defun sas-page-fix (start)
800 "Fix page numbers in sas output from point to end of file.
801 If START is given this will be the number for the current page."
802 (interactive "P")
803 (let (offset (pnum (sas-page-number)))
804 (if (not start) (setq offset 0)
805 (setq offset (- start pnum)))
806 (while (not (eobp))
807 (sas-fix-page-numbers offset pnum)
808 (setq pnum (1+ pnum))
809 (forward-page 1))))
811 (defun fix-page-breaks ()
812 "Fix page breaks in SAS 6 print files."
813 (interactive)
814 (save-excursion
815 (goto-char (point-min))
816 (if (looking-at "\f") (delete-char 1))
817 (replace-regexp "^\\(.+\\)\f" "\\1\n\f\n")
818 (goto-char (point-min))
819 (replace-regexp "^\f\\(.+\\)" "\f\n\\1")
820 (goto-char (point-min))
821 (replace-regexp "
822 $" "")
823 (goto-char (point-min))
824 (replace-regexp "
825 \\([^
826 \\$]+\\)" "\n\\1")
827 (goto-char (point-max))
828 (if (not (bobp))
829 (progn (backward-char 1)
830 (if (not (looking-at "\n"))
831 (progn (forward-char 1) (open-line 1)))))))
833 (defun sas-page-number ()
834 ;; like what-page except it returns an integer page number
835 "Return page number of point in current buffer."
836 (let ((opoint (point))) (save-excursion
837 (goto-char (point-min))
838 (1+ (sas-how-many page-delimiter opoint)))))
840 (defun sas-how-many (regexp &optional end)
841 ;; a copy of `how-many' which returns an integer
842 ;; rather than a message
843 "Return number of matches for REGEXP following point."
844 (let ((count 0) opoint)
845 (save-excursion
846 (while (and (not (eobp))
847 (progn (setq opoint (point))
848 (re-search-forward regexp end t)))
849 (if (= opoint (point))
850 (forward-char 1)
851 (setq count (1+ count))))
852 count)))
854 (defun beginning-of-sas-proc ()
855 "Move point to beginning of sas proc, macro or data step."
856 (interactive)
857 (let ((case-fold-search t))
858 (forward-char -1)
859 (while (not (or (looking-at "data\\|proc\\|%macro")
860 (bobp)))
861 (re-search-backward "proc\\|data\\|%macro" (point-min) 1)
862 (beginning-of-sas-statement 1))))
864 (defun next-sas-proc (arg)
865 "Move point to beginning of next sas proc."
866 (interactive "P")
867 (let ((case-fold-search t))
868 (forward-char 1)
869 (if (re-search-forward
870 "^[ \t]*\\(data[ ;]\\|proc[ ;]\\|endsas[ ;]\\|g?options[ ;]\\|%macro[ ;]\\)"
871 nil t arg)
872 (beginning-of-sas-statement 1)
873 (forward-char -1))))
875 (defun set-sas-file-name ()
876 "Stores the name of the current sas file."
877 (let ((name (buffer-file-name)))
878 (cond ((not name))
879 ((string-match (substring name -4 nil)
880 "\\.sas\\|\\.lst\\|\\.log")
882 (setq sas-file-name (substring name 0 (- (length name) 4)))
883 (setq sas-buffer-name (buffer-name))
884 (setq sas-file-root (substring sas-buffer-name 0
885 (- (length sas-buffer-name) 4))))
886 (t (message "This file does not have a standard suffix")))))
888 ;; created 6/27/94
889 (defun sas-set-alternate-file-name (name)
890 "Stores the NAME of an alternate sas file.
891 When this file is submitted with `submit-sas', the alternate file will
892 be submitted instead. `sas-submitable' is automatically sets to t."
893 (interactive "f")
894 (cond ((string-match (substring name -4 nil)
895 "\\.sas\\|\\.lst\\|\\.log")
896 (setq sas-file-name (substring name 0 (- (length name) 4)))
897 (setq sas-submitable t))
898 (t (message "This file does not have a standard suffix"))))
900 (defun switch-to-sas-source ()
901 "Switches to sas source file associated with the current file."
902 (interactive)
903 (switch-to-sas-file "sas"))
905 (defun switch-to-sas-lst ()
906 "Switches to sas source file associated with the current file."
907 (interactive)
908 (switch-to-sas-file "lst"))
910 (defun switch-to-sas-log ()
911 "Switches to sas source file associated with the current file."
912 (interactive)
913 (switch-to-sas-file "log"))
915 (defun switch-to-sas-source-other-window ()
916 "Switches to sas source file associated with the current file."
917 (interactive)
918 (switch-to-sas-file-other-window "sas"))
920 (defun switch-to-sas-lst-other-window ()
921 "Switches to sas source file associated with the current file."
922 (interactive)
923 (switch-to-sas-file-other-window "lst"))
925 (defun switch-to-sas-log-other-window ()
926 "Switches to sas source file associated with the current file."
927 (interactive)
928 (switch-to-sas-file-other-window "log"))
930 ;;(defun switch-to-sas-file (suff &optional revert silent)
931 ;; "Switches to sas \"SUFF\" file associated with the current file"
932 ;; (let* ((sfile sas-file-name)
933 ;; (buf (get-file-buffer (concat sfile "." suff)))
934 ;; (sas-require-confirmation
935 ;; (and sas-require-confirmation (not revert))))
936 ;; (if (or sas-require-confirmation (string-equal suff "sas") (not buf))
937 ;; (find-file (concat sfile "." suff))
938 ;; (progn (switch-to-buffer buf)
939 ;; (if (not (verify-visited-file-modtime (current-buffer)))
940 ;; (progn (revert-buffer t t)
941 ;; (if (not silent)
942 ;; (message "File has changed on disk. Buffer automatically updated."))))))
943 ;; (setq sas-file-name sfile))
944 ;; (if (string-equal suff "sas")
945 ;; (if (not (string-equal major-mode "sas-mode"))
946 ;; (sas-mode))
947 ;; (if (not (string-equal major-mode "sasl-mode"))
948 ;; (sasl-mode))))
950 ;;(defun switch-to-sas-file-other-window (suff)
951 ;; "Switches to sas \"SUFF\" file associated with the current file"
952 ;; (let* ((sfile sas-file-name)
953 ;; (buf (get-file-buffer (concat sfile "." suff))))
954 ;; (if (or sas-require-confirmation (string-equal suff "sas") (not buf))
955 ;; (find-file-other-window (concat sfile "." suff))
956 ;; (progn (switch-to-buffer-other-window buf)
957 ;; (if (not (verify-visited-file-modtime (current-buffer)))
958 ;; (progn (revert-buffer t t)
959 ;; (message "File has changed on disk. Buffer automatically updated.")))))
960 ;; (setq sas-file-name sfile))
961 ;; (if (string-equal suff "sas")
962 ;; (if (not (string-equal major-mode "sas-mode"))
963 ;; ;;(sas-mode)
964 ;; )
965 ;; (if (not (string-equal major-mode "sasl-mode"))
966 ;; ;;(sasl-mode)
967 ;; )))
969 (defun switch-to-sas-file (suff)
970 "Switches to sas \"SUFF\" file associated with the current file."
971 (switch-to-buffer (set-sas-file-buffer suff)))
973 (defun switch-to-sas-file-other-window (suff)
974 "Switches to sas \"SUFF\" file associated with the current file."
975 (switch-to-buffer-other-window (set-sas-file-buffer suff)))
977 ;; The following was created 6/7/94 to handle buffers without messing up
978 ;; windows.
980 (defun set-sas-file-buffer (suff &optional revert silent)
981 "Sets current buffer to sas \"SUFF\" file associated with the current file."
982 (let* ((sfile sas-file-name)
983 (buf (get-file-buffer (concat sfile "." suff)))
984 (sas-require-confirmation
985 (and sas-require-confirmation (not revert))))
986 (if (or sas-require-confirmation (string-equal suff "sas") (not buf))
987 (set-buffer (find-file-noselect (concat sfile "." suff)))
988 (progn (set-buffer buf)
989 (if (not (verify-visited-file-modtime (current-buffer)))
990 (progn (revert-buffer t t)
991 (if (not silent)
992 (message "File has changed on disk. Buffer automatically updated."))))))
993 (setq sas-file-name sfile))
994 ;;(if (string-equal suff "sas")
995 ;; (if (not (string-equal major-mode "sas-mode")) (sas-mode))
996 ;; (if (not (string-equal major-mode "sasl-mode"))(sasl-mode))
997 (current-buffer))
999 (defun switch-to-sas-process-buffer ()
1000 "Switch to sas-process-buffer."
1001 (interactive)
1002 (let (buf proc-name)
1003 (setq proc-name (concat "SAS" sas-file-name)
1004 buf (concat "*" proc-name "*"))
1005 (switch-to-buffer-other-window buf)))
1007 (defun submit-sas ()
1008 ;; 6/17/94 added sas-submitable local variable.
1009 "Submit SAS file as shell command."
1010 (interactive)
1011 (if ;; can file be run, or is it only for inclusion?
1012 (or sas-submitable
1013 (progn
1014 (beep)
1015 (y-or-n-p
1016 (format
1017 "Submission is disabled for this file. Submit it anyway? "))))
1018 (progn
1019 ;; if buffer name has changed, tell user
1020 (if (or
1021 (string-equal sas-buffer-name (buffer-name))
1022 (not
1023 (y-or-n-p
1024 (format
1025 "The name of this buffer has changed. Submit the new file? "))))
1026 (setq sas-buffer-name (buffer-name))
1027 (set-sas-file-name))
1028 (let ((sas-file sas-file-name)
1029 (sas-root sas-file-root)
1030 ;;(sas-buf sas-buffer-name)
1031 proc-name
1032 buf)
1034 ;; Save buffer to SAS the right file :-).
1035 (if (buffer-modified-p)
1036 (if (y-or-n-p (format "Buffer %s is modified. Save it? "
1037 (buffer-name)))
1038 (save-buffer)))
1039 (setq proc-name (concat "SAS" sas-file)
1040 buf (concat "*" proc-name "*"))
1041 (if (get-buffer buf)
1042 (save-window-excursion (switch-to-buffer buf)
1043 (erase-buffer)
1044 (setq default-directory
1045 (file-name-directory sas-file))))
1047 (run-hooks 'sas-pre-run-hook) ;; added 8/24/94
1048 (message "---- Submitting SAS job ----")
1049 ;; (switch-to-buffer buf)
1050 (make-comint proc-name
1051 sas-program ;added sas-program 4/29/94
1053 sas-root)
1054 (save-window-excursion
1055 (switch-to-buffer buf)
1056 (setq sas-file-name sas-file)
1057 (bury-buffer buf))
1059 (message "---- SAS job submitted ---- ")
1061 (if sas-notify;; added 4/7/94
1062 (set-process-sentinel (get-process proc-name) 'sas-sentinel)
1063 (display-buffer buf t))))
1064 (message "---- File not submitted ----")))
1066 ;; 5/2/94 Modified sas-sentinel to check for errors in log file upon
1067 ;; completion.
1068 (defun sas-sentinel (proc arg);; created 4/7/94
1069 "Notify user that SAS run is done."
1070 (beep)
1071 ;;(if (string-equal arg "finished\n")
1072 (save-excursion
1073 (let (msg buf win (sbuf (concat "*" (process-name proc) "*")))
1074 (setq msg
1075 (format "SAS %s %s"
1076 (substring arg 0 -1)
1077 (if sas-error-notify
1078 ;;(save-window-excursion
1079 (progn
1080 (set-buffer sbuf)
1081 (setq buf (set-sas-file-buffer "log" t t))
1082 (goto-char (point-min))
1083 (setq win (get-buffer-window buf))
1084 (save-window-excursion
1085 (if win
1086 (progn
1087 (select-window win)
1088 (if (re-search-forward "^ERROR" nil t)
1089 " (See .log file for errors)"
1090 ""))
1091 (switch-to-buffer buf)
1092 (if (re-search-forward "^ERROR" nil t)
1093 " (See .log file for errors)"
1094 ""))))
1095 "")))
1096 (set-buffer sbuf)
1097 (goto-char (point-max))
1098 (insert msg)
1099 (bury-buffer (get-buffer sbuf))
1100 ;;(if (and sas-notify-popup window-system)
1101 ;; (x-popup-dialog t
1102 ;; (list "SAS Menu" (cons msg nil) )))
1103 ;;(if (not (minibuffer-window-active-p)) (princ msg))
1104 (princ msg))))
1106 ;; 5/2/94 Modified run-sas-on-region to separate log and output buffers.
1108 ;;(defun run-sas-on-region (start end append &optional buffer)
1109 ;; "Submit region to SAS"
1110 ;; (interactive "r\nP")
1111 ;; (message "---- Running SAS ----")
1112 ;; (let ((sfile sas-file-name)
1113 ;; (shell-file-name "/bin/sh")
1114 ;; serror buff)
1115 ;; (setq buffer (or buffer "*SAS output*"))
1116 ;; (save-excursion
1117 ;; (shell-command-on-region
1118 ;; start end;; added sas-program
1119 ;; (concat sas-program " -nonews -stdio 2> /tmp/_temp_.log" nil))
1120 ;; (get-buffer-create "*SAS Log*")
1121 ;; (save-window-excursion
1122 ;; (switch-to-buffer "*SAS Log*")
1123 ;; (erase-buffer)
1124 ;; (insert-file-contents "/tmp/_temp_.log")
1125 ;; (delete-file "/tmp/_temp_.log")
1126 ;; (setq serror (re-search-forward "^ERROR" nil t))
1127 ;; (if serror () (bury-buffer)))
1128 ;; (setq buff (get-buffer-create buffer))
1129 ;; (save-window-excursion
1130 ;; (switch-to-buffer buff)
1131 ;; (setq sas-file-name sfile)
1132 ;; (if append
1133 ;; (progn
1134 ;; (end-of-buffer)
1135 ;; (insert "\f\n"))
1136 ;; (erase-buffer))
1137 ;; (if (get-buffer "*Shell Command Output*")
1138 ;; (progn (insert-buffer "*Shell Command Output*")
1139 ;; (kill-buffer "*Shell Command Output*"))
1140 ;; (insert "SAS completed with no output."))
1141 ;; (if append () (sasl-mode))
1142 ;; (message "---- SAS Complete ----")))
1143 ;; (if (not serror)
1144 ;; (switch-to-buffer-other-window buff)
1145 ;; (switch-to-buffer-other-window "*SAS Log*")
1146 ;; (goto-char serror)
1147 ;; (beep)
1148 ;; (message "Error found in log file.")
1149 ;; )))
1151 (defun switch-to-dataset-log-buffer ()
1152 "Switch to log buffer for run-sas-on-region."
1153 (interactive)
1154 (switch-to-buffer-other-window "*SAS Log*"))
1156 (defun switch-to-dataset-source-buffer ()
1157 "Switch to source buffer for run-sas-on-region."
1158 (interactive)
1159 (switch-to-buffer-other-window (format " *sas-tmp-%s*" sas-dataset)))
1161 ;;(defun sas-get-dataset (filename &optional arg opts-p append buffer vars)
1162 ;; "Run proc contents and proc print on SAS dataset. Automatically prompts
1163 ;;for SAS options to use. Default options are defined by the variable
1164 ;;`sas-get-options'. Output may be updated from within output buffer with
1165 ;;C-cr if dataset changes. Also, the source code which generates the output
1166 ;;may be edited with C-cs. Typing C-cr within the output buffer reexecutes
1167 ;;the (modified) source code."
1168 ;; (interactive "fName of SAS dataset (file name):")
1169 ;; (let ((file (file-name-nondirectory filename))
1170 ;; (dir (file-name-directory filename))
1171 ;; (opts sas-get-options)
1172 ;; (minibuffer-history sas-get-options-history)
1173 ;; buf); fsize)
1174 ;; (setq buffer (or buffer (concat "*" file "*")))
1175 ;; (setq opts (if opts-p opts (read-string "SAS options: " opts)))
1176 ;; (setq sas-get-options-history minibuffer-history)
1177 ;; (cond ((string-match (substring file -6 nil) "\\.ssd01")
1178 ;; (setq file (substring file 0 (- (length file) 6))))
1179 ;; (t (error "This file is not a SAS dataset.")))
1180 ;; (setq buf (format " *sas-tmp-%s*" file))
1181 ;; (get-buffer-create buf)
1182 ;; (save-window-excursion
1183 ;; (switch-to-buffer buf)
1184 ;; (erase-buffer)
1185 ;; (setq default-directory dir)
1186 ;; (if opts
1187 ;; (insert (format "options %s ;\n" opts)))
1188 ;; (insert (format "title \"Contents of SAS dataset `%s'\" ;\n" file))
1189 ;; (insert (format "libname %s '%s' ;\n" sas-tmp-libname dir))
1190 ;; (if (not (equal arg 1))
1191 ;; (insert (format "proc contents data = %s.%s ;\n" sas-tmp-libname file)))
1192 ;; (if (equal arg 2) ()
1193 ;; (insert (format "proc print data = %s.%s ;\n" sas-tmp-libname file))
1194 ;; (if vars (insert (format " var %s ;\n" vars))))
1195 ;; (run-sas-on-region (point-min) (point-max) append
1196 ;; buffer)
1197 ;; (get-buffer buffer)
1198 ;; (if append () (sasd-mode)) ;; added 5/5/94
1199 ;; (setq sas-dataset file))
1200 ;; (if (get-buffer-window buffer t)
1201 ;; (raise-frame (window-frame (get-buffer-window buffer t)))
1202 ;; (display-buffer buffer (not append)))
1203 ;; ))
1205 ;;(defun revert-sas-dataset ()
1206 ;; "Revert current sas dataset from disk version"
1207 ;; (interactive)
1208 ;; (let* ((file sas-dataset)
1209 ;; (buf (format " *sas-tmp-%s*" file))
1210 ;; (pos (point)))
1211 ;; (save-window-excursion
1212 ;; (switch-to-buffer buf)
1213 ;; (run-sas-on-region (point-min) (point-max) nil
1214 ;; (concat "*" file ".ssd01*"))
1215 ;; )
1216 ;; (goto-char pos) ;; added 6/9/94
1217 ;; (sasd-mode) ;; added 5/5/94
1218 ;; (setq sas-dataset file)))
1220 (defun sas-insert-local-variables () ;; created 6/17/94
1221 "Add local variables code to end of sas source file."
1222 (interactive)
1223 (save-excursion
1224 (if (re-search-forward "* *Local Variables: *;" nil t)
1226 (goto-char (point-max))
1227 (insert "
1229 ** Local Variables: ;
1230 ** End: ;
1231 page ;
1232 "))))
1236 ;;-*-emacs-lisp-*-
1237 ;;; file name: sas-data.el
1239 ;;; Version 1.0
1241 ;;; sas-data-mode: manage sas datasets
1242 ;;; Copyright (C) 1994 Tom Cook
1244 ;;; This program is free software; you can redistribute it and/or modify
1245 ;;; it under the terms of the GNU General Public License as published by
1246 ;;; the Free Software Foundation; either version 2 of the License, or
1247 ;;; (at your option) any later version.
1249 ;;; This program is distributed in the hope that it will be useful,
1250 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
1251 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1252 ;;; GNU General Public License for more details.
1254 ;;; You should have received a copy of the GNU General Public License
1255 ;;; along with this program; if not, write to the Free Software
1256 ;;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
1258 ;;; Author: Tom Cook
1259 ;;; Dept. of Biostatistics
1260 ;;; University of Wisconsin - Madison
1261 ;;; Madison, WI 53706
1262 ;;; cook@biostat.wisc.edu
1263 ;; Created: 8/11/94
1265 ;; variables section
1266 (defvar sas-dir-mode-map nil)
1267 (defvar sas-directory-name nil
1268 "Name of directory associated with this buffer.")
1269 (make-variable-buffer-local 'sas-directory-name)
1270 (defvar sas-dir-buf-end nil)
1271 (make-variable-buffer-local 'sas-dir-buf-end)
1272 (defvar sas-sorted-by-num nil)
1273 (make-variable-buffer-local 'sas-sorted-by-num)
1274 ;; user variables
1276 ;; keymaps etc...
1278 (if sas-dir-mode-map ()
1279 (setq sas-dir-mode-map (make-sparse-keymap))
1280 ;;(define-key sas-dir-mode-map "c" 'sas-contents)
1281 (define-key sas-dir-mode-map "p" 'sas-print)
1282 (define-key sas-dir-mode-map "m" 'sas-mark-item)
1283 (define-key sas-dir-mode-map "u" 'sas-unmark-item)
1284 (define-key sas-dir-mode-map " " 'sas-next-line)
1285 (define-key sas-dir-mode-map "\C-n" 'sas-next-line)
1286 (define-key sas-dir-mode-map "\C-p" 'sas-prev-line)
1287 (define-key sas-dir-mode-map "\177" 'sas-prev-line-undo)
1288 (define-key sas-dir-mode-map "\C-b" 'sas-backward-page-narrow)
1289 (define-key sas-dir-mode-map "\C-v" 'sas-forward-page-narrow)
1290 (define-key sas-dir-mode-map "\C-m" 'sas-goto-dataset)
1291 (define-key sas-dir-mode-map [mouse-2] 'sas-mouse-goto-dataset)
1292 (define-key sas-dir-mode-map "t" 'sas-dir-goto-page)
1293 (define-key sas-dir-mode-map "q" 'bury-buffer)
1294 (define-key sas-dir-mode-map "g" 'sas-revert-library)
1295 (define-key sas-dir-mode-map "1" 'digit-argument)
1296 (define-key sas-dir-mode-map "2" 'digit-argument)
1297 (define-key sas-dir-mode-map "3" 'digit-argument)
1298 (define-key sas-dir-mode-map "4" 'digit-argument)
1299 (define-key sas-dir-mode-map "5" 'digit-argument)
1300 (define-key sas-dir-mode-map "6" 'digit-argument)
1301 (define-key sas-dir-mode-map "7" 'digit-argument)
1302 (define-key sas-dir-mode-map "8" 'digit-argument)
1303 (define-key sas-dir-mode-map "9" 'digit-argument)
1304 (define-key sas-dir-mode-map [menu-bar sas run]
1305 '("Submit File " . submit-sas))
1308 ;(require 'sas)
1310 (defun sas-dir-mode ()
1311 "Major mode for managing sas files."
1312 (interactive)
1313 (kill-all-local-variables)
1314 (use-local-map sas-dir-mode-map)
1315 (setq major-mode 'sas-dir-mode)
1316 (setq mode-name "SAS")
1317 (setq sas-directory-name (expand-file-name default-directory))
1318 (toggle-read-only 1))
1321 ;;(defun sas-make-library (directory &optional update)
1322 ;; "Create a buffer with the names of all sas datasets from DIRECTORY."
1323 ;; (interactive "DDirectory Name: ")
1324 ;; (let ((dir (expand-file-name directory)) buf out cont pos)
1325 ;; (setq buf (format " *sas-tmp-%s*" dir))
1326 ;; (setq out (concat "*SAS-dir-" dir))
1327 ;; (setq cont (concat "*SAS-cont-" dir))
1328 ;; (get-buffer-create buf)
1329 ;; (if (get-buffer out)
1330 ;; (if update
1331 ;; (progn
1332 ;; (set-buffer out)
1333 ;; (setq buffer-read-only nil)))
1334 ;; (setq update t))
1335 ;; (pop-to-buffer out)
1336 ;; (setq default-directory dir)
1337 ;; (setq pos (point))
1338 ;; (if update
1339 ;; (progn
1340 ;; (save-window-excursion
1341 ;; (set-buffer buf)
1342 ;; (erase-buffer)
1343 ;; (setq default-directory dir)
1344 ;; (insert "options linesize=70 pagesize=1000 ;\n")
1345 ;; (insert (format "title \"Contents of SAS directory `%s'\" ;\n"
1346 ;; dir))
1347 ;; (insert (format "libname %s '%s' ;\n" sas-tmp-libname dir))
1348 ;; (insert (format "proc contents data = %s._all_ directory details memtype=data ;\n" sas-tmp-libname))
1349 ;; (run-sas-on-region (point-min) (point-max) nil
1350 ;; out)
1351 ;; (set-buffer out)
1352 ;; (goto-char (point-min))
1353 ;; (if (= (sas-how-many page-delimiter (point-max)) 0)
1354 ;; (let ((buffer-read-only nil))
1355 ;; (erase-buffer)
1356 ;; (insert "There are no SAS datasets in this directory")
1357 ;; (pop-to-buffer out))
1358 ;; (save-excursion
1359 ;; (set-buffer (get-buffer-create cont))
1360 ;; (setq buffer-read-only t)
1361 ;; (let ((buffer-read-only nil))
1362 ;; (erase-buffer)
1363 ;; (insert-buffer out)
1364 ;; (delete-region (point-min)
1365 ;; (or (re-search-forward page-delimiter nil t)
1366 ;; (point-min)))
1367 ;; (sas-page-fix 1)
1368 ;; (goto-char (point-min))
1369 ;; (sas-dir-mode)
1370 ;; (sas-narrow-to-page)))
1371 ;; (if (re-search-forward page-delimiter nil t)
1372 ;; (delete-region (progn (beginning-of-line) (point))
1373 ;; (point-max)))
1374 ;; (sas-insert-set-properties (point-min) (point-max))
1375 ;; )
1376 ;; (switch-to-buffer out t)
1377 ;; (goto-char (point-min))
1378 ;; (sas-dir-mode)
1379 ;; (setq sas-dir-buf-end (point-max)))
1380 ;; (goto-char pos)
1381 ;; (sas-move-to-filename (point-max))))))
1384 (defun sas-move-to-filename (&optional eol)
1385 (or eol (setq eol (progn (end-of-line) (point))))
1386 (beginning-of-line)
1387 (if (re-search-forward "\\(^ *[0-9]+ *<*\\)[^:0-9\n]" eol t)
1388 (goto-char (match-end 1))))
1390 (defun sas-next-line (arg)
1391 "Move down one line."
1392 (interactive "p")
1393 (forward-line arg)
1394 (sas-move-to-filename (point-max)))
1395 ;;(and (< (point) sas-dir-buf-end)
1396 ;;(forward-line arg)
1397 ;;(sas-move-to-filename sas-dir-buf-end)))
1399 (defun sas-prev-line (arg)
1400 "Move up one line."
1401 (interactive "p")
1402 (beginning-of-line)
1403 (re-search-backward "^ *[0-9]+ *<*[^:0-9\n]" (point-min) t)
1404 (sas-move-to-filename sas-dir-buf-end))
1406 (defun sas-insert-set-properties (beg end)
1407 (save-excursion
1408 (goto-char beg)
1409 (while (< (point) end)
1410 (if (sas-move-to-filename)
1411 (put-text-property (point)
1412 (+ 8 (point))
1413 'mouse-face 'highlight))
1414 (forward-line 1))))
1416 (defun sas-get-filename ()
1417 "Return name of dataset on current line."
1418 (interactive)
1419 (save-excursion
1420 (if (string-equal "*SAS-dir" (substring (buffer-name) 0 8))
1421 (sas-move-to-filename)
1422 (goto-char (point-min))
1423 (re-search-forward "Data Set Name: [^.]*\\."))
1424 (expand-file-name
1425 (downcase (concat sas-directory-name
1426 (buffer-substring
1427 (point)
1428 (save-excursion
1429 (skip-chars-forward "A-Z0-9_")
1430 (point))) ".ssd01")))))
1432 (defun sas-get-file-number ()
1433 "Return name of dataset on current line."
1434 (interactive)
1435 (if (sas-move-to-filename)
1436 (progn (forward-word -1)
1437 (re-search-forward "[0-9]*")
1438 (string-to-number
1439 (buffer-substring (match-beginning 0)
1440 (match-end 0))))))
1442 ;;(defun sas-contents ()
1443 ;; "Run proc contents on current file."
1444 ;; (interactive)
1445 ;; (let ((buffer-read-only nil) (sas-get-options "linesize=70"))
1446 ;; (sas-get-dataset (sas-get-filename) 2 t t (buffer-name))
1447 ;; (end-of-buffer)
1448 ;; (backward-page-top-of-window 1)))
1450 ;;(defun sas-print ()
1451 ;; "Run proc contents on current file."
1452 ;; (interactive)
1453 ;; (sas-get-dataset (sas-get-filename) 1 nil nil nil
1454 ;; (sas-create-var-string)))
1456 (defun sas-goto-page (arg)
1457 "Goto top of page ARG. If no ARG, then goto top of file."
1458 (interactive "P")
1459 (goto-char 1)
1460 (if arg
1461 (if (> arg 1)
1462 (progn
1463 (re-search-forward page-delimiter (point-max) 1 (1- arg)))))
1464 (skip-chars-forward sas-white-chars); was " \f\n" till 5.1.13
1465 (recenter 1))
1467 (defun forward-page-top-of-window (arg)
1468 "Move forward to page boundary and leave first line at top of window.
1469 With arg, repeat, or go back if negative. A page boundary is any line
1470 whose beginning matches the regexp `page-delimiter'."
1471 (interactive "p")
1472 (forward-page arg)
1473 (recenter 0))
1475 (defun backward-page-top-of-window (arg)
1476 "Move backward to page boundary and leave first line at top of window.
1477 With arg, repeat, or go back if negative. A page boundary is any line
1478 whose beginning matches the regexp `page-delimiter'."
1479 (interactive "p")
1480 (forward-page (- arg))
1481 (recenter 0))
1483 (defun sas-narrow-to-page ()
1484 (save-excursion
1485 (let* ((min (point-min))
1486 (max (point-max)))
1487 ;;(omin (point-min))
1488 ;;(omax (point-max)))
1489 (if (or (bolp) (beginning-of-line)
1490 (looking-at page-delimiter))
1491 (forward-char 1)
1492 (forward-page -1))
1493 (setq min (point))
1494 (forward-page 1)
1495 (beginning-of-line)
1496 (setq max (point))
1497 (narrow-to-region min max))))
1499 (defun sas-forward-page-narrow (arg)
1500 "Move forward to page boundary and narrow to page.
1501 With arg, repeat, or go back if negative. A page boundary is any line
1502 whose beginning matches the regexp `page-delimiter'."
1503 (interactive "p")
1504 (widen)
1505 (forward-page arg)
1506 (sas-narrow-to-page)
1507 (goto-char (point-min)))
1509 (defun sas-backward-page-narrow (arg)
1510 "Move backward to page boundary and narrow to page.
1511 With arg, repeat, or go back if negative. A page boundary is any line
1512 whose beginning matches the regexp `page-delimiter'."
1513 (interactive "p")
1514 (goto-char (point-min))
1515 (widen)
1516 (forward-page (- arg))
1517 (sas-narrow-to-page))
1519 (defun sas-goto-dataset (&optional page)
1520 (interactive)
1521 (and sas-directory-name
1522 (let ((page (or page (sas-get-file-number))))
1523 ;;(dir sas-directory-name))
1524 (if page
1525 (progn
1526 (switch-to-buffer-other-window
1527 (concat "*SAS-cont-" sas-directory-name))
1528 (widen)
1529 (sas-goto-page page)
1530 (sas-narrow-to-page)
1531 (goto-char (point-min)))))))
1533 ;;(defun sas-mouse-goto-dataset (event)
1534 ;; (interactive "e")
1535 ;; (let (page buf)
1536 ;; (save-window-excursion
1537 ;; (save-excursion
1538 ;; (set-buffer (window-buffer (posn-window (event-end event))))
1539 ;; (save-excursion
1540 ;; (goto-char (posn-point (event-end event)))
1541 ;; (setq page (sas-get-file-number)))
1542 ;; (sas-goto-dataset page)
1543 ;; (setq buf (buffer-name))))
1544 ;; (set-buffer buf)
1545 ;; (goto-char (point-min))
1546 ;; (display-buffer buf)))
1549 (defun sas-dir-goto-page (page)
1550 (interactive "p")
1551 (widen)
1552 (sas-goto-page page)
1553 (sas-narrow-to-page))
1555 (defun sas-mark-item (&optional next)
1556 (interactive)
1557 (sas-move-to-filename)
1558 (beginning-of-line)
1559 (let ((buffer-read-only nil))
1560 (if (re-search-forward "^\\( *[0-9]+ *\\) \\([A-Z][A-Z_0-9]*\\) "
1561 (save-excursion (end-of-line) (point)) t)
1562 (replace-match "\\1<\\2>")))
1563 (or next (sas-next-line 1)))
1565 (defun sas-unmark-item ()
1566 (interactive)
1567 (save-excursion
1568 (beginning-of-line)
1569 (let ((buffer-read-only nil))
1570 (if (re-search-forward "^\\( *[0-9]+ *\\)<\\([A-Z][A-Z_0-9]*\\)>"
1571 (save-excursion (end-of-line) (point)) t)
1572 (replace-match "\\1 \\2 ")))))
1574 (defun sas-prev-line-undo (arg)
1575 (interactive "p")
1576 (sas-prev-line arg)
1577 (sas-unmark-item)
1578 (sas-move-to-filename))
1580 (defun sas-create-var-string ()
1581 (and (string-equal "*SAS-cont" (substring (buffer-name) 0 9))
1582 (let (str)
1583 (goto-char (point-min))
1584 (while
1585 (re-search-forward "^\\( *[0-9]+ *\\)<\\([A-Z][A-Z_0-9]*\\)>"
1586 nil t)
1587 (setq str (concat str " " (buffer-substring (match-beginning 2)
1588 (match-end 2)))))
1589 str)))
1591 ;;(defun sas-revert-library ()
1592 ;; "Update current library."
1593 ;; (interactive)
1594 ;; (if sas-directory-name
1595 ;; (sas-make-library sas-directory-name t)))
1597 (provide 'essl-sas)
1599 \f ; Local variables section
1601 ;;; This file is automatically placed in Outline minor mode.
1602 ;;; The file is structured as follows:
1603 ;;; Chapters: ^L ;
1604 ;;; Sections: ;;*;;
1605 ;;; Subsections: ;;;*;;;
1606 ;;; Components: defuns, defvars, defconsts
1607 ;;; Random code beginning with a ;;;;* comment
1608 ;;; Local variables:
1609 ;;; mode: emacs-lisp
1610 ;;; mode: outline-minor
1611 ;;; outline-regexp: "\^L\\|\\`;\\|;;\\*\\|;;;\\*\\|(def[cvu]\\|(setq\\|;;;;\\*"
1612 ;;; End:
1614 ;;; essl-sas.el ends here