home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 3 / 3376 < prev    next >
Encoding:
Internet Message Format  |  1991-05-21  |  24.9 KB

  1. From: jv@mh.nl (Johan Vromans)
  2. Newsgroups: gnu.emacs.sources,alt.sources
  3. Subject: GNU Emacs forms-mode version 1.2.2, part 2 of 3
  4. Message-ID: <1991May20.093108.1496@pronto.mh.nl>
  5. Date: 20 May 91 09:31:08 GMT
  6.  
  7. Submitted-by: jv@mh.nl
  8. Archive-name: forms/part02
  9.  
  10. ---- Cut Here and feed the following to sh ----
  11. #!/bin/sh
  12. # this is forms.shr.02 (part 2 of forms)
  13. # do not concatenate these parts, unpack them in order with /bin/sh
  14. # file forms.ti continued
  15. #
  16. if test ! -r _shar_seq_.tmp; then
  17.     echo 'Please unpack part 1 first!'
  18.     exit 1
  19. fi
  20. (read Scheck
  21.  if test "$Scheck" != 2; then
  22.     echo Please unpack part "$Scheck" next!
  23.     exit 1
  24.  else
  25.     exit 0
  26.  fi
  27. ) < _shar_seq_.tmp || exit 1
  28. if test ! -f _shar_wnt_.tmp; then
  29.     echo 'x - still skipping forms.ti'
  30. else
  31. echo 'x - continuing file forms.ti'
  32. sed 's/^X//' << 'SHAR_EOF' >> 'forms.ti' &&
  33. X
  34. @end table
  35. X
  36. @node Miscellaneous, Error Messages, Key Bindings, Top
  37. @section Miscellaneous
  38. X
  39. @vindex forms-version
  40. A global variable ``forms-version'' holds the version information of
  41. the current implementation of forms mode.
  42. X
  43. Care has been taken to localize the current information of the forms
  44. mode, so it is possible to visit multiple files in forms mode
  45. simultaneously, even if they have different properties.
  46. X
  47. If a control file is visited using the standard @code{find-file}
  48. commands, forms mode can be enabled with the command @code{M-x forms-mode}.@*
  49. Forms mode will be automatically enabled if the file contains
  50. the string @code{"-*- forms -*-"} somewhere in the first line. However,
  51. this makes it hard to edit the control file itself so you'd better think
  52. twice before using this.
  53. X
  54. The default format for the data file, using @key{TAB} to separate fields
  55. and @code{C-k} to separate multi-line fields, matches the file format of
  56. some popular Macintosh database programs, e.g. FileMaker. So
  57. @code{forms-mode} could decrease the need to use Apple computers.
  58. X
  59. @node Error Messages, Credits, Miscellaneous, Top
  60. @section Error Messages
  61. X
  62. This section describes all error messages which can be generated by
  63. forms mode.
  64. X
  65. @table @code
  66. @item 'forms-file' has not been set
  67. The variable @code{forms-file} was not set by the control file.
  68. X
  69. @item 'forms-number-of-fields' has not been set
  70. The variable @code{forms-number-of-fields} was not set by the control
  71. file.
  72. X
  73. @item 'forms-number-of-fields' must be > 0
  74. The variable @code{forms-number-of-fields} did not contain a positive
  75. number. 
  76. X
  77. @item 'forms-field-sep' is not a string
  78. @itemx 'forms-multi-line' must be nil or a one-character string
  79. The variable @code{forms-multe-line} was set to something other than
  80. @code{nil or} a single-character string.
  81. X
  82. @item 'forms-multi-line' is equal to 'forms-field-sep'
  83. The variable @code{forms-multi-line} may not be equal to
  84. @code{forms-field-sep} for this would make it impossible to distinguish
  85. fields and the lines in the fields.
  86. X
  87. @item 'forms-format-list' has not been set
  88. @itemx 'forms-format-list' is not a list
  89. The variable @code{forms-format-list} was not set to a lisp @code{list}
  90. by the control file.
  91. X
  92. @item forms error: field number @var{XX} out of range 1..@var{NN}
  93. A field number was supplied with a value of @var{XX}, which was not
  94. greater that zero and smaller than or equal to the number of fields in the
  95. forms, @var{NN}.
  96. X
  97. @item invalid element in 'forms-format-list': @var{XX}
  98. A list element was supplied in @code{forms-format-list} which was not a
  99. @code{string} nor a @code{number}.
  100. X
  101. @item parse error: not looking at "@var{TEXT}"
  102. When re-parsing the contents of a forms, the text @var{TEXT}, which
  103. starts the forms, could not be found.
  104. X
  105. @item parse error: cannot find "@var{TEXT}"
  106. When re-parsing the contents of a forms, the text @var{TEXT}, which
  107. separates two fields, could not be found.
  108. X
  109. @item parse error: cannot parse adjacent fields @var{XX} and @var{YY}
  110. Fields @var{XX} and @var{YY} were not separated by text, so could not be
  111. parsed again.
  112. X
  113. @item Record has @var{XX} fields instead of @var{YY}
  114. The number of fields in this record in the data file did not match
  115. @code{forms-number-of-fields}. Missing fields will be set to empty.
  116. X
  117. @item Multi-line fields in this record - update refused!
  118. The current record contains newline characters, hance can not be written
  119. back to the data file, for it would corrupt it.@*
  120. probably a field was set to a multi-line value, while the setting of
  121. @code{forms-multi-line} prohibited this.
  122. X
  123. @item Record number @var{XX} out of range 1..@var{YY}
  124. A jump was made to non-existing record @var{XX}. @var{YY} denotes the
  125. number of records in the file.
  126. X
  127. @item Stuck at record @var{XX}
  128. An internal error prevented a specific record from being retrieved.
  129. X
  130. @end table
  131. X
  132. @node Credits, Concept Index, Error Messages, Top
  133. @section Credits
  134. X
  135. Forms mode is developed by Johan Vromans @code{<jv@@mh.nl>} at Multihouse
  136. Reseach in the Netherlands. 
  137. X
  138. Harald Hanche-Olsen @code{<hanche@@imf.unit.no>} supplied the idea for
  139. the new record filter, and provided better replacements for some
  140. internal functions. 
  141. X
  142. Bugfixes and other useful suggestions were supplied by
  143. cwitty@@portia.stanford.edu, Jonathan I. Kamens, Ignatios Souvatzis and
  144. Harald Hanche-Olsen.
  145. X
  146. This documentation was slightly inspired by the documentation of ``rolo
  147. mode'' by Paul Davis at Schlumberger Cambridge Research
  148. @code{<davis%scrsu1%sdr.slb.com@@relay.cs.net>}.
  149. X
  150. None of this would have been possible without GNU Emacs of the Free
  151. Software Foundation. Thanks, Richard!
  152. X
  153. @node Concept Index, Variable Index, Credits, Top
  154. @unnumbered Concept Index
  155. @printindex cp
  156. X
  157. @node Variable Index, Function Index, Concept Index, Top
  158. @unnumbered Variable Index
  159. @printindex vr
  160. X
  161. @node Function Index, , Variable Index, Top
  162. @unnumbered Function Index
  163. @printindex fn
  164. X
  165. @contents
  166. @bye
  167. SHAR_EOF
  168. echo 'File forms.ti is complete' &&
  169. chmod 0444 forms.ti ||
  170. echo 'restore of forms.ti failed'
  171. Wc_c="`wc -c < 'forms.ti'`"
  172. test 21930 -eq "$Wc_c" ||
  173.     echo 'forms.ti: original size 21930, current size' "$Wc_c"
  174. rm -f _shar_wnt_.tmp
  175. fi
  176. # ============= forms.el ==============
  177. if test -f 'forms.el' -a X"$1" != X"-c"; then
  178.     echo 'x - skipping forms.el (File already exists)'
  179.     rm -f _shar_wnt_.tmp
  180. else
  181. > _shar_wnt_.tmp
  182. echo 'x - extracting forms.el (Text)'
  183. sed 's/^X//' << 'SHAR_EOF' > 'forms.el' &&
  184. ;;; Forms Mode - A GNU Emacs Major Mode        ; @(#)@ forms    1.2.2
  185. ;;; Created 1989 - Johan Vromans <jv@mh.nl>
  186. ;;; See the docs for a list of other contributors.
  187. ;;;
  188. ;;; This file is part of GNU Emacs.
  189. X
  190. ;;; GNU Emacs is distributed in the hope that it will be useful,
  191. ;;; but WITHOUT ANY WARRANTY.  No author or distributor
  192. ;;; accepts responsibility to anyone for the consequences of using it
  193. ;;; or for whether it serves any particular purpose or works at all,
  194. ;;; unless he says so in writing.  Refer to the GNU Emacs General Public
  195. ;;; License for full details.
  196. X
  197. ;;; Everyone is granted permission to copy, modify and redistribute
  198. ;;; GNU Emacs, but only under the conditions described in the
  199. ;;; GNU Emacs General Public License.   A copy of this license is
  200. ;;; supposed to have been given to you along with GNU Emacs so you
  201. ;;; can know your rights and responsibilities. 
  202. ;;; If you don't have this copy, write to the Free Software
  203. ;;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  204. ;;;
  205. X
  206. (provide 'forms-mode)
  207. X
  208. ;;; Visit a file using a form.
  209. ;;;
  210. ;;; === Naming conventions
  211. ;;;
  212. ;;; The names of all variables and functions start with 'form-'.
  213. ;;; Names which start with 'form--' are intended for internal use, and
  214. ;;; should *NOT* be used from the outside.
  215. ;;;
  216. ;;; All variables are buffer-local, to enable multiple forms visits 
  217. ;;; simultaneously.
  218. ;;; Variable 'forms--mode-setup' is local to *ALL* buffers, for it 
  219. ;;; controls if forms-mode has been enabled in a buffer.
  220. ;;;
  221. ;;; === How it works ===
  222. ;;;
  223. ;;; Forms mode means visiting a data file which is supposed to consist
  224. ;;; of records each containing a number of fields. The records are
  225. ;;; separated by a newline, the fields are separated by a user-defined
  226. ;;; field separater (default: TAB).
  227. ;;; When shown, a record is transferred to an emacs buffer and
  228. ;;; presented using a user-defined form. One record is shown at a
  229. ;;; time.
  230. ;;;
  231. ;;; Forms mode is a composite mode. It involves two files, and two
  232. ;;; buffers.
  233. ;;; The first file, called the control file, defines the name of the
  234. ;;; data file and the forms format. This file buffer will be used to
  235. ;;; present the forms.
  236. ;;; The second file holds the actual data. The buffer of this file
  237. ;;; will be buried, for it is never accessed directly.
  238. ;;;
  239. ;;; Forms mode is invoked using "forms-find-file control-file".
  240. ;;; Alternativily forms-find-file-other-window can be used.
  241. ;;;
  242. ;;; You may also visit the control file, and switch to forms mode by hand
  243. ;;; with M-x forms-mode .
  244. ;;;
  245. ;;; Automatic mode switching is supported, so you may use "find-file"
  246. ;;; if you specify "-*- forms -*-" in the first line of the control file.
  247. ;;; 
  248. ;;; The control file is visited, evaluated using
  249. ;;; eval-current-buffer, and should set at least the following
  250. ;;; variables:
  251. ;;;
  252. ;;;    forms-file            [string] the name of the data file.
  253. ;;;
  254. ;;;    forms-number-of-fields        [integer]
  255. ;;;            The number of fields in each record.
  256. ;;;
  257. ;;;    forms-format-list           [list]   formatting instructions.
  258. ;;;
  259. ;;; The forms-format-list should be a list, each element containing
  260. ;;;
  261. ;;;  - either a string, e.g. "hello" (which is inserted \"as is\"),
  262. ;;;
  263. ;;;  - an integer, denoting a field number. The contents of the field
  264. ;;;    are inserted at this point.
  265. ;;;    The first field has number one.
  266. ;;;
  267. ;;; Optional variables which may be set in the control file:
  268. ;;;
  269. ;;;    forms-field-sep                [string, default TAB]
  270. ;;;            The field separator used to separate the
  271. ;;;            fields in the data file. It may be a string.
  272. ;;;
  273. ;;;    forms-read-only                [bool, default nil]
  274. ;;;            't' means that the data file is visited read-only.
  275. ;;;            If no write access to the data file is
  276. ;;;            possible, read-only mode is enforced. 
  277. ;;;
  278. ;;;    forms-multi-line            [string, default "^K"]
  279. ;;;            If non-null the records of the data file may
  280. ;;;            contain fields which span multiple lines in
  281. ;;;            the form.
  282. ;;;            This variable denoted the separator character
  283. ;;;            to be used for this purpose. Upon display, all
  284. ;;;            occurrencies of this character are translated
  285. ;;;            to newlines. Upon storage they are translated
  286. ;;;            back to the separator.
  287. ;;;
  288. ;;;    forms-forms-scroll            [bool, default t]
  289. ;;;            If non-nil: redefine scroll-up/down to perform
  290. ;;;            forms-next/prev-field if in forms mode.
  291. ;;;
  292. ;;;    forms-forms-jump            [bool, default t]
  293. ;;;            If non-nil: redefine beginning/end-of-buffer
  294. ;;;            to performs forms-first/last-field if in
  295. ;;;            forms mode.
  296. ;;;
  297. ;;;    forms-new-record-filter            [function, no default]
  298. ;;;            If defined: this function is called when a new
  299. ;;;            record is created. It can be used to fill in
  300. ;;;            the new record with default fields, for example.
  301. ;;;
  302. ;;; After evaluating the control file, its buffer is cleared and used
  303. ;;; for further processing.
  304. ;;; The data file (as designated by "forms-file") is visited in a buffer
  305. ;;; (forms--file-buffer) which will not normally be shown.
  306. ;;; Great malfunctioning may be expected if this file/buffer is modified
  307. ;;; outside of this package while it's being visited!
  308. ;;;
  309. ;;; A record from the data file is transferred from the data file,
  310. ;;; split into fields (into forms--the-record-list), and displayed using
  311. ;;; the specs in forms-format-list.
  312. ;;; A format routine 'forms--format' is build upon startup to format 
  313. ;;; the records.
  314. ;;;
  315. ;;; When a form is changed the record is updated as soon as this form
  316. ;;; is left. The contents of the form are parsed using forms-format-list,
  317. ;;; and the fields which are deduced from the form are modified. So,
  318. ;;; fields not shown on the forms retain their origional values.
  319. ;;; The newly formed record and replaces the contents of the
  320. ;;; old record in forms--file-buffer.
  321. ;;; A parse routine 'forms--parser' is build upon startup to parse
  322. ;;; the records.
  323. ;;;
  324. ;;; Two exit functions exist: forms-exit (which saves) and forms-exit-no-save
  325. ;;; (which doesn't). However, if forms-exit-no-save is executed and the file
  326. ;;; buffer has been modified, emacs will ask questions.
  327. ;;;
  328. ;;; Other functions are:
  329. ;;;
  330. ;;;    paging (forward, backward) by record
  331. ;;;    jumping (first, last, random number)
  332. ;;;    searching
  333. ;;;    creating and deleting records
  334. ;;;    reverting the form (NOT the file buffer)
  335. ;;;    switching edit <-> view mode v.v.
  336. ;;;    jumping from field to field
  337. ;;;
  338. ;;; As an documented side-effect: jumping to the last record in the
  339. ;;; file (using forms-last-record) will adjust forms--total-records if
  340. ;;; needed.
  341. ;;;
  342. ;;; Commands and keymaps:
  343. ;;;
  344. ;;; A local keymap 'forms-mode-map' is used in the forms buffer.
  345. ;;; As conventional, this map can be accessed with C-c prefix.
  346. ;;; In read-only mode, the C-c prefix must be omitted.
  347. ;;;
  348. ;;; Default bindings:
  349. ;;;
  350. ;;;    \C-c    forms-mode-map
  351. ;;;    TAB    forms-next-field
  352. ;;;    SPC     forms-next-record
  353. ;;;    <    forms-first-record
  354. ;;;    >    forms-last-record
  355. ;;;    ?    describe-mode
  356. ;;;    d    forms-delete-record
  357. ;;;    e    forms-edit-mode
  358. ;;;    i    forms-insert-record
  359. ;;;    j    forms-jump-record
  360. ;;;    n    forms-next-record
  361. ;;;    p    forms-prev-record
  362. ;;;    q    forms-exit
  363. ;;;    s    forms-search
  364. ;;;    v    forms-view-mode
  365. ;;;    x    forms-exit-no-save
  366. ;;;    DEL    forms-prev-record
  367. ;;;
  368. ;;; Standard functions scroll-up, scroll-down, beginning-of-buffer and
  369. ;;; end-of-buffer are wrapped with re-definitions, which map them to
  370. ;;; next/prev record and first/last record.
  371. ;;; Buffer-local variables forms-forms-scroll and forms-forms-jump
  372. ;;; may be used to control these redefinitions.
  373. ;;;
  374. ;;; Function save-buffer is also wrapped to perform a sensible action.
  375. ;;; A revert-file-hook is defined to revert a forms to original.
  376. ;;;
  377. ;;; For convenience, TAB is always bound to forms-next-field, so you
  378. ;;; don't need the C-c prefix for this command.
  379. ;;;
  380. ;;; Global variables and constants
  381. X
  382. (defconst forms-version "1.2.2"
  383. X  "Version of forms-mode implementation")
  384. X
  385. (defvar forms-forms-scrolls t
  386. X  "If non-null: redefine scroll-up/down to be used with forms-mode.")
  387. X
  388. (defvar forms-forms-jumps t
  389. X  "If non-null: redefine beginning/end-of-buffer to be used with forms-mode.")
  390. X
  391. (defvar forms-mode-hooks nil
  392. X  "Hook functions to be run upon entering forms mode.")
  393. ;;;
  394. ;;; Mandatory variables - must be set by evaluating the control file
  395. X
  396. (defvar forms-file nil
  397. X   "Name of the file holding the data.")
  398. X
  399. (defvar forms-format-list nil
  400. X  "Formatting specifications:
  401. X
  402. It should be a list, each element containing 
  403. X
  404. X - either a string, e.g. "hello" (which is inserted \"as is\"),
  405. X
  406. X - an integer, denoting the number of a field which contents are
  407. X   inserted at this point.
  408. X   The first field has number one.
  409. ")
  410. X
  411. (defvar forms-number-of-fields nil
  412. X  "Number of fields per record.")
  413. X
  414. ;;;
  415. ;;; Optional variables with default values
  416. X
  417. (defvar forms-field-sep "\t"
  418. X  "Field separator character (default TAB)")
  419. X
  420. (defvar forms-read-only nil
  421. X  "Read-only mode (defaults to the write access on the data file).")
  422. X
  423. (defvar forms-multi-line "\C-k"
  424. X  "Character to separate multi-line fields (default ^K)")
  425. X
  426. (defvar forms-forms-scroll t
  427. X  "Redefine scroll-up/down to perform forms-next/prev-record when in
  428. X forms mode.")
  429. X
  430. (defvar forms-forms-jump t
  431. X  "Redefine beginning/end-of-buffer to perform forms-first/last-record
  432. X when in forms mode.")
  433. X
  434. ;;;
  435. ;;; Internal variables.
  436. X
  437. (defvar forms--file-buffer nil
  438. X  "Buffer which holds the file data")
  439. X
  440. (defvar forms--total-records 0
  441. X  "Total number of records in the data file.")
  442. X
  443. (defvar forms--current-record 0
  444. X  "Number of the record currently on the screen.")
  445. X
  446. (defvar forms-mode-map nil        ; yes - this one is global
  447. X   "Keymap for form buffer.")
  448. X
  449. (defvar forms--markers nil
  450. X  "Field markers in the screen.")
  451. X
  452. (defvar forms--number-of-markers 0
  453. X  "Number of fields on screen.")
  454. X
  455. (defvar forms--the-record-list nil 
  456. X   "List of strings of the current record, as parsed from the file.")
  457. X
  458. (defvar forms--search-regexp nil
  459. X  "Last regexp used by forms-search.")
  460. X
  461. (defvar forms--format nil
  462. X  "Formatting routine.")
  463. X
  464. (defvar forms--parser nil
  465. X  "Forms parser routine.")
  466. X
  467. (defvar forms--mode-setup nil
  468. X  "Internal - keeps track of forms-mode being set-up.")
  469. (make-variable-buffer-local 'forms--mode-setup)
  470. X
  471. (defvar forms--new-record-filter nil
  472. X  "Internal - set if a new record filter has been defined.")
  473. X
  474. ;;;
  475. ;;; forms-mode
  476. ;;;
  477. ;;; This is not a simple major mode, as usual. Therefore, forms-mode
  478. ;;; takes an optional argument 'primary' which is used for the initial
  479. ;;; set-up. Normal use would leave 'primary' to nil.
  480. ;;;
  481. ;;; A global buffer-local variable 'forms--mode-setup' has the same effect
  482. ;;; but makes it possible to auto-invoke forms-mode using find-file.
  483. ;;;
  484. ;;; Note: although it seems logical to have (make-local-variable) executed
  485. ;;; where the variable is first needed, I deliberately placed all calls
  486. ;;; in the forms-mode function.
  487. (defun forms-mode (&optional primary)
  488. X  "Major mode to visit files in a field-structured manner using a form.
  489. X
  490. X Commands (prefix with C-c if not in read-only mode):
  491. X \\{forms-mode-map}"
  492. X
  493. X  (interactive)                ; no - 'primary' is not prefix arg
  494. X
  495. X  ;; Primary set-up: evaluate buffer and check if the mandatory
  496. X  ;; variables have been set.
  497. X  (if (or primary (not forms--mode-setup))
  498. X      (progn
  499. X    (kill-all-local-variables)
  500. X
  501. X    ;; make mandatory variables
  502. X    (make-local-variable 'forms-file)
  503. X    (make-local-variable 'forms-number-of-fields)
  504. X    (make-local-variable 'forms-format-list)
  505. X
  506. X    ;; make optional variables
  507. X    (make-local-variable 'forms-field-sep)
  508. X        (make-local-variable 'forms-read-only)
  509. X        (make-local-variable 'forms-multi-line)
  510. X    (make-local-variable 'forms-forms-scroll)
  511. X    (make-local-variable 'forms-forms-jump)
  512. X    (fmakunbound 'forms-new-record-filter)
  513. X
  514. X    ;; eval the buffer, should set variables
  515. X    (eval-current-buffer)
  516. X
  517. X    ;; check if the mandatory variables make sense.
  518. X    (or forms-file
  519. X        (error "'forms-file' has not been set"))
  520. X    (or forms-number-of-fields
  521. X        (error "'forms-number-of-fields' has not been set"))
  522. X    (or (> forms-number-of-fields 0)
  523. X        (error "'forms-number-of-fields' must be > 0")
  524. X    (or (stringp forms-field-sep))
  525. X        (error "'forms-field-sep' is not a string"))
  526. X    (if forms-multi-line
  527. X        (if (and (stringp forms-multi-line)
  528. X             (eq (length forms-multi-line) 1))
  529. X        (if (string= forms-multi-line forms-field-sep)
  530. X            (error "'forms-multi-line' is equal to 'forms-field-sep'"))
  531. X          (error "'forms-multi-line' must be nil or a one-character string")))
  532. X        
  533. X    ;; validate and process forms-format-list
  534. X    (make-local-variable 'forms--number-of-markers)
  535. X    (make-local-variable 'forms--markers)
  536. X    (forms--process-format-list)
  537. X
  538. X    ;; build the formatter and parser
  539. X    (make-local-variable 'forms--format)
  540. X    (forms--make-format)
  541. X    (make-local-variable 'forms--parser)
  542. X    (forms--make-parser)
  543. X
  544. X    ;; check if a new record filter was defined
  545. X    (make-local-variable 'forms--new-record-filter)
  546. X    (setq forms--new-record-filter 
  547. X          (and (fboundp 'forms-new-record-filter)
  548. X           (symbol-function 'forms-new-record-filter)))
  549. X    (fmakunbound 'forms-new-record-filter)
  550. X
  551. X
  552. X    ;; prepare this buffer for further processing
  553. X    (setq buffer-read-only nil)
  554. X
  555. X    ;; prevent accidental overwrite of the control file and autosave
  556. X    (setq buffer-file-name nil)
  557. X    (auto-save-mode nil)
  558. X
  559. X    ;; and clean it
  560. X    (erase-buffer)))
  561. X
  562. X  ;; make local variables
  563. X  (make-local-variable 'forms--file-buffer)
  564. X  (make-local-variable 'forms--total-records)
  565. X  (make-local-variable 'forms--current-record)
  566. X  (make-local-variable 'forms--the-record-list)
  567. X  (make-local-variable 'forms--search-rexexp)
  568. X
  569. X  ;; A bug in the current Emacs release prevents a keymap
  570. X  ;; which is buffer-local from being used by 'describe-mode'.
  571. X  ;; Hence we'll leave it global.
  572. X  ;;(make-local-variable 'forms-mode-map)
  573. X  (if forms-mode-map            ; already defined
  574. X      nil
  575. X    (setq forms-mode-map (make-keymap))
  576. X    (forms--mode-commands forms-mode-map)
  577. X    (forms--change-commands))
  578. X
  579. X  ;; find the data file
  580. X  (setq forms--file-buffer (find-file-noselect forms-file))
  581. X
  582. X  ;; count the number of records, and set see if it may be modified
  583. X  (let (ro)
  584. X    (setq forms--total-records
  585. X      (save-excursion
  586. X        (set-buffer forms--file-buffer)
  587. X        (bury-buffer (current-buffer))
  588. X        (setq ro buffer-read-only)
  589. X        (count-lines (point-min) (point-max))))
  590. X    (if ro
  591. X    (setq forms-read-only t)))
  592. X
  593. X  ;; set the major mode indicator
  594. X  (setq major-mode 'forms-mode)
  595. X  (setq mode-name "Forms")
  596. X  (make-local-variable 'minor-mode-alist) ; needed?
  597. X  (forms--set-minor-mode)
  598. X  (forms--set-keymaps)
  599. X
  600. X  (set-buffer-modified-p nil)
  601. X
  602. X  ;; We have our own revert function - use it
  603. X  (make-local-variable 'revert-buffer-function)
  604. X  (setq revert-buffer-function 'forms-revert-buffer)
  605. X
  606. X  ;; setup the first (or current) record to show
  607. X  (if (< forms--current-record 1)
  608. X      (setq forms--current-record 1))
  609. X  (forms-jump-record forms--current-record)
  610. X
  611. X  ;; user customising
  612. X  (run-hooks 'forms-mode-hooks)
  613. X
  614. X  ;; be helpful
  615. X  (forms--help)
  616. X
  617. X  ;; initialization done
  618. X  (setq forms--mode-setup t))
  619. X
  620. ;;;
  621. ;;; forms-process-format-list
  622. ;;;
  623. ;;; Validates forms-format-list.
  624. ;;;
  625. ;;; Sets forms--number-of-markers and forms--markers.
  626. X
  627. (defun forms--process-format-list ()
  628. X  "Validate forms-format-list and set some global variables."
  629. X
  630. X  ;; it must be non-nil
  631. X  (or forms-format-list
  632. X      (error "'forms-format-list' has not been set"))
  633. X  ;; it must be a list ...
  634. X  (or (listp forms-format-list)
  635. X      (error "'forms-format-list' is not a list"))
  636. X
  637. X  (setq forms--number-of-markers 0)
  638. X
  639. X  (let ((the-list forms-format-list)    ; the list of format elements
  640. X    (field-num 0))            ; highest field number 
  641. X
  642. X    (while the-list
  643. X
  644. X      (let ((el (car-safe the-list))
  645. X        (rem (cdr-safe the-list)))
  646. X
  647. X    (cond
  648. X
  649. X     ;; try string ...
  650. X     ((stringp el))            ; string is OK
  651. X      
  652. X     ;; try int ...
  653. X     ((numberp el)            ; check it
  654. X
  655. X      (if (or (<= el 0)
  656. X          (> el forms-number-of-fields))
  657. X          (error
  658. X           "forms error: field number %d out of range 1..%d"
  659. X           el forms-number-of-fields))
  660. X
  661. X      (setq forms--number-of-markers (1+ forms--number-of-markers))
  662. X      (if (> el field-num)
  663. X          (setq field-num el)))
  664. X
  665. X     ;; else
  666. X     (t
  667. X      (error "invalid element in 'forms-format-list': %s"
  668. X         (prin1-to-string el)))
  669. X
  670. X     ;; dead code - we'll need it in the future
  671. X     ((consp el)            ; check it
  672. X
  673. X      (let ((str (car-safe el))
  674. X        (idx (cdr-safe el)))
  675. X
  676. X        (cond
  677. X
  678. X         ;; car must be string
  679. X         ((not (stringp str))
  680. X          (error "forms error: car of cons %s must be string"
  681. X             (prin1-to-string el)))
  682. X
  683. X         ;; cdr must be number, > zero
  684. X         ((or (not (numberp idx))
  685. X          (<= idx 0)
  686. X          (> idx forms-number-of-fields))
  687. X          (error
  688. X           "forms error: cdr of cons %s must be a number between 1 and %d"
  689. X           (prin1-to-string el)
  690. X           forms-number-of-fields)))
  691. X
  692. X        ;; passed the test - handle it
  693. X        (setq forms--number-of-markers (1+ forms--number-of-markers))
  694. X        (if (> idx field-num)
  695. X        (setq field-num idx)))))
  696. X
  697. X    ;; advance to next element of the list
  698. X    (setq the-list rem))))
  699. X
  700. X  (setq forms--markers (make-vector forms--number-of-markers nil)))
  701. X
  702. X
  703. ;;;
  704. ;;; Build the format routine from forms-format-list.
  705. ;;;
  706. ;;; The format routine (forms--format) will look like
  707. ;;; 
  708. ;;; (lambda (arg)
  709. ;;;
  710. ;;;   ;;  "text: "
  711. ;;;   (insert "text: ")
  712. ;;;   ;;  6
  713. ;;;   (aset forms--markers 0 (point-marker))
  714. ;;;   (insert (elt arg 5))
  715. ;;;   ;;  "\nmore text: "
  716. ;;;   (insert "\nmore text: ")
  717. ;;;   ;;  9
  718. ;;;   (aset forms--markers 1 (point-marker))
  719. ;;;   (insert (elt arg 8))
  720. ;;;
  721. ;;;   ... )
  722. ;;; 
  723. X
  724. (defun forms--make-format ()
  725. X  "Generate parser function for forms"
  726. X  (setq forms--format (forms--format-maker forms-format-list)))
  727. X
  728. (defun forms--format-maker (the-format-list)
  729. X  "Returns the parser function for forms"
  730. X  (let ((the-marker 0))
  731. X    (` (lambda (arg)
  732. X     (,@ (apply 'append
  733. X            (mapcar 'forms--make-format-elt 
  734. X                (forms--concat-adjacent the-format-list))))))))
  735. X
  736. (defun forms--make-format-elt (el)
  737. X  (cond ((stringp el)
  738. X     (` ((insert (, el)))))
  739. X    ((numberp el)
  740. X     (prog1
  741. X         (` ((aset forms--markers (, the-marker) (point-marker))
  742. X         (insert (elt arg (, (1- el))))))
  743. X       (setq the-marker (1+ the-marker))))))
  744. X
  745. X
  746. (defun forms--concat-adjacent (the-list)
  747. X  "Concatenate adjacent strings in the-list and return the resulting list"
  748. X  (if (consp the-list)
  749. X      (let ((the-rest (forms--concat-adjacent (cdr the-list))))
  750. X    (if (and (stringp (car the-list)) (stringp (car the-rest)))
  751. X        (cons (concat (car the-list) (car the-rest))
  752. X          (cdr the-rest))
  753. X        (cons (car the-list) the-rest)))
  754. X      the-list))
  755. ;;;
  756. ;;; forms--make-parser.
  757. ;;;
  758. ;;; Generate parse routine from forms-format-list.
  759. ;;;
  760. ;;; The parse routine (forms--parser) will look like (give or take
  761. ;;; a few " " .
  762. ;;; 
  763. ;;; (lambda nil
  764. ;;;   (let (here)
  765. ;;;     (goto-char (point-min))
  766. ;;; 
  767. ;;;    ;;  "text: "
  768. ;;;     (if (not (looking-at "text: "))
  769. ;;;         (error "parse error: cannot find \"text: \""))
  770. SHAR_EOF
  771. true || echo 'restore of forms.el failed'
  772. fi
  773. echo 'End of forms part 2'
  774. echo 'File forms.el is continued in part 3'
  775. echo 3 > _shar_seq_.tmp
  776. exit 0
  777. -- 
  778. Johan Vromans                       jv@mh.nl via internet backbones
  779. Multihouse Automatisering bv               uucp: ..!{uunet,hp4nl}!mh.nl!jv
  780. Doesburgweg 7, 2803 PL Gouda, The Netherlands  phone/fax: +31 1820 62911/62500
  781. ------------------------ "Arms are made for hugging" -------------------------
  782.