;; This file: gellmu.el ;; ;; The GELLMU Syntactic Translator ;; ;; By William F. Hammond ;; ;; GELLMU stands for ``Generalized Extensible LaTeX-Like MarkUp''. ;; This Elisp program, for use with Gnu-Emacs (version 19 or higher), ;; may be used to convert a document with GELLMU's LaTeX-Like markup ;; to a document in an authoring language under Standard Generalized ;; Markup Language (SGML) or, if desired, to a document under ;; eXtensible Markup Language (XML). ;; ;; Copyright (C) 1999-2007 by William F. Hammond ;; ;; 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 2 of the ;; License, or (at your option) any later version. ;; ;; A copy of this license is available at the same location as this ;; program; simply substitute "LICENSE" for "gellmu.el" in the ;; full resource name for this file. ;; ;; This program is distributed in the hope that it will be useful, but ;; WITHOUT ANY WARRANTY, without even an implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;; General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ;; ;; Author's Address: ;; Department of Mathematics & Statistics ;; The University at Albany ;; 1400 Washington Avenue ;; Albany, New York 12222 ;; USA ;; ;; Author's Email: hammond@math.albany.edu ;; ;; The said License does not permit incorporating this program into ;; proprietary programs. There may, however, be permissible ways to use ;; it; see the license. ;; ====================================================================== ;; Be aware that: ;; ;; (1) GELLMU is not LaTeX. ;; ;; (2) There is no completely reliable way to convert legacy ;; LaTeX to an SGML or XML language. ;; See the docs. ;; A first level outline of this code is available by searching for lines ;; beginning with the string " ;;" (three spaces, two semi-colons). ;; ;; Elementary Usage: ;; ;; -- Interactive -- ;; ;; M-x load-library gellmu ;; ;; Then one of the following: ;; ;; M-x gellmu-trans ;; M-x gellmu-html ;; M-x gellmu-sgml ;; M-x gellmu-xml ;; ;; after saving your GELLMU markup but not closing Emacs. gellmu-trans ;; will place its output in a separate buffer. For a complete list ;; ;; -- Batch Mode -- ;; ;; emacs -batch -l ./gellmu.el -f gellmu-trans myfoo.glm ;; OR ;; emacs -batch -l ./gellmu.el -f _function-name_ myfoo.glm ;; ;; The first usage is for "advanced" GELLMU. Roughly, the other ;; function calls are for "basic" GELLMU (for only the simplest ;; layer of LaTeX-like syntax) or for hybrid usage. ;; ;; IMPORTANT: Any form of GELLMU requires knowledge of the ;; SGML or XML document type for which the author is writing. ;; ;; Advanced Gellmu with the didactic "article" document type has many ;; names that match corresponding LaTeX names. Someone with knowledge ;; of LaTeX should be able to prepare a simple "article" by using ;; "\documenttype{article}" instead of LaTeX's "\documentclass{article}". ;; The preamble ends with "\begin{document}", and the document ends ;; with "\end{document}". Blank lines begin new paragraphs. ;; ;; For "article" under the function call gellmu-trans aside from that ;; just mentioned: ;; ;; o There must be a \title{...} in the preamble although it ;; may be empty, i.e., \title{} ;; ;; o Inline markup may not be loose in the document body (between ;; \begin{document} and \end{document}. At the very least it ;; must be in a paragraph, and a paragraph may be begun with ;; a blank line. ;; ;; Document Type Identification ;; ;; If your document is to be LaTeX-like "article", make the first ;; line ;; ;; \documenttype{article} , ;; ;; which references the didactic document type represented by ;; "gellmu.dtd". ;; ;; For full flexibility there is a key system for attaching a sequence ;; of document type information to a key that is supplied with ;; ;; \documenttype[keystring]{doctype-name} ;; ;; The option is treated as a SYSTEM identifier unless its value appears ;; as a key for the associative list gellmu-doctype-info. ;; ;; Moreover, each doctype-name may appear as a key for the associative ;; list gellmu-doctype-keylist. ;; ;; Thus, ;; \documenttype{article} ;; ;; spawns "gellmu.dtd" because "article" is by default assigned ;; the key "gellmuart" with gellmu-doctype-keylist and "gellmuart" ;; is assigned the sequence ("SYSTEM", "gellmu.dtd") with ;; gellmu-doctype-info. ;; ;; The same effect would be obtained with the usage ;; ;; \documenttype[gellmuart]{article} . ;; ;; Other examples: ;; ;; \documenttype{html} ;; ;; picks up the key "html-4.01", which, in turn, spawns the sequence ;; ("PUBLIC", "-//W3C//DTD HTML 4.01 Transitional//EN"), while ;; ;; \documenttype[xhtml-1.0]{html} ;; ;; spawns the sequence ;; ("xml", "PUBLIC", "-//W3C//DTD XHTML 1.0 Transitional//EN", ;; "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd", ;; "UTF-8", "xmlns=\"http://www.w3.org/1999/xhtml\"") , ;; ;; \documenttype[xhtml-1.0s]{html} ;; ;; changes "transitional" in the previous example to "strict", and ;; ;; \documenttype[mathml-altheim]{html} ;; ;; references ;; ("xml", "PUBLIC", "-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN", ;; "mathml.dtd", "UTF-8", "xmlns=\"http://www.w3.org/1999/xhtml\"") . ;; ;; In the larger GELLMU design support of legacy LaTeX is not the main ;; goal. Keeping the syntactic translator free of more than minimal ;; command-name intelligence is a goal. That makes it possible to use ;; LaTeX-like markup practice as a general markup interface to *any* ;; SGML or XML language ;; ;; (defvar gellmu-version "0.7.4.8" "Version number of the library \"gellmu\"") (defvar gellmu-version-date "16-Jan-2014" "Date of the current source version (\"gellmu.el\") of the library \"gellmu\"" ) ;; CHANGES: ;; ;; 0.7.4.7 -> 0.7.4.8 * Added "html-5" to doctype-info and made it the ;; 16-Jan-2014 default for the "html" document-type ;; ;; 0.7.4.6 -> 0.7.4.7 * Changed value of variable gellmu-sgml-default-coding ;; 20-Sep-2010 from "iso-latin-1" to "utf-8" ;; ;; 0.7.4.5 -> 0.7.4.6 * Change: removed tolerance of omitted spec for ;; 25-May-2008 the number of arguments of a newcommand ;; ;; 0.7.4.4 -> 0.7.4.5 * Cleaned handling of (what-line) in messages ;; 29-Jun-2007 and fixed a bug in error message code inside ;; balance-pair-forward ;; ;; 0.7.4.3 -> 0.7.4.4 ;; 03-Jun-2007 * Better handling of mismatched newcommand args ;; ;; * In LaTeX emulation run diagnostics for the ;; balancing of '$' characters (toggle math zones) ;; ;; 0.7.4.2 -> 0.7.4.3 ;; 01-Feb-2007 * Code the strings "'''" and "''''" as \rtq and \rqq ;; and then the loose "`" and "'" as \lsq and \rsq ;; ;; 0.7.4.1 -> 0.7.4.2 ;; 05-Jan-2006 * Corrected failed attempt to generate warnings ;; about loose '#' in source ;; ;; 0.7.4 -> 0.7.4.1 ;; 29-Aug-2004 * Corrected definition of variable ;; gellmu-tab-amp-tail ;; ;; 0.7.3 -> 0.7.4 ;; ;; 04-Aug-2004 * For "regular" handling added translation of "\@" ;; to and of "\/" to . ;; ;; 02-Aug-2004 * Added vect, mscript, setOf, overset, underset ;; to gellmu-autoclose-list (for "regular" handling) ;; ;; 11-Jul-2004 * Corrected overzealous safety check of ;; 07-Jul-2001. It is intended that the ;; name of a newcommand may be used at the ;; beginning of its value string in order to ;; "front" document type names. The previous ;; code blocked the use of \ab in the definition ;; of \a. ;; ;; * Provide for decimal numeric character entities ;; outside of newcommand arguments. OK in macro. ;; (The char entity form &#x is not ambiguous.) ;; ;; * Provided escape "\#" to make literal '#' safe ;; (when followed by an integer) in newcommand ;; values. (\# had been documented to do this.) ;; ;; * Corrected obsolete call to concat to prepend ;; "#" to an integer in the course of processing ;; invocations of \newcommand with arguments. ;; ;; 0.7.2 -> 0.7.3: * Provided some looping safety for \newcommand: ;; 07-Jul-2001 Exit with error if there is a self reference ;; in (unexpanded) definition beyond its location 1 ;; ;; * Small bug in newcommand handling: pick up ;; point for next invocation one char too soon. ;; ;; ;; 0.7.1 -> 0.7.2: * Use first \documenttype option "" to avoid ;; 11-Jun-2001 writing "" and root tags ;; altogether. Use first option "INTERNAL" for ;; "" under SGML rules ;; where the internal declaration subset comes, ;; as always, from the \documenttype option that ;; follows its sole argument. For XML rules ;; instead of SGML rules, use "XINTERNAL". ;; ;; * Code for the internal declaration subset now ;; accepts \attlist{} and \element{} in addition ;; to \entity{} and \notation{}, and all of these ;; names are now configurable (so one can avoid ;; possible name conflicts). ;; ;; * Bug: "\%" in internal declaration subset source ;; is now converted to "%". ;; ;; * Provided variable gellmu-hold-xml-introducer ;; for blocking the writing of an XML declaration. ;; ;; * Provided variable gellmu-procinst-name ;; for a meta-command that may be used consciously ;; to enter a processing instruction. ;; ;; Tried and then backed out change moving pick up ;; point for newcommand substitutions moved from one ;; character beyond the beginning of the ;; substitution point to the end of the last ;; occurrence of the invocation string ;; introducer in the expanded substitution if ;; there is such an occurrence. Perhaps at some ;; point this would be useful for something called ;; "\frontcommand" rather than "\newcommand". ;; ;; 05-Jun-2001 * Provided variable gellmu-parb-everywhere ;; and calling function gellmu-part-advanced for ;; allowing parb handling with fragments of ;; advanced gellmu documents. ;; ;; * Provided variable gellmu-doc-fragment and ;; calling function gellmu-part-basic for ;; facilitating the preparation of document ;; fragments with documenttype handling. ;; ;; * What was called "regular GELLMU" (the full ;; layer of LaTeX syntactic emulation) is now ;; called "advanced GELLMU" (in comments here) ;; ;; 0.7.0 -> 0.7.1: * Bug: blocked writing of "nul" and friends ;; 27-May-2001 in cleanup for "\macro", "\newcommand", ;; and "\Macro" (late macros) except when ;; gellmu-regular-sgml is false (advanced gellmu) ;; ;; * Bug: pick up point in the loop for making ;; newcommand substitutions was at the end of ;; the last completed substitution rather ;; than one character beyond its origin. ;; ;; * Provided item in gellmu-doctype-info for a ;; list of attribute settings for the root tag ;; under basic GELLMU in the XML case ;; ;; * Bug fixes: ;; ;; * Code for encoding item in gellmu-doctype-info ;; supplied ;; ;; * \documenttype with empty option fouled up; ;; should simply suppress DOCTYPE declaration but ;; provide root open and close tags. Useful to ;; override setting of root tag key. ;; ;; * When \documenttype option is not a known key ;; and therefore must be a SYSTEM identifier, ;; URIs are now accepted. (Added the chars ;; `/', `:', `%', and `~' to the internal variable ;; gellmu-doctype-opt-regexp) ;; ;; * In XML mode at point where possible unbalanced ;; open tag warning was issued, no open tag was ;; written. ;; ;; ;; 0.6.9 -> 0.7.0: * New version level. No plans for new features. ;; 26-Mar-2001 ;; ;; 0.6.8 -> 0.6.9: ;; ;; * Revised code for quophrase and squophrase to ;; attempt detection of loose apostrophes and ;; (right) single quotes inside quophrase and ;; squophrase zones. Not completely foolproof. ;; Sometimes explicit markup is required. ;; ;; * Fixed error with buffer-substring overreach ;; ;; * Revised tab-amp code to treat as tabcell ;; when followed either by blank or newline ;; (gives sgml entity when followed by other things) ;; ;; * Changed \macro to \Macro and then cloned ;; the code for \Macro to new code for \macro ;; that comes first. So the macro processing ;; sequence is now: ;; ;; 1. macro 2. mathsym 3. newcommand 4. Macro. ;; ;; This reflects the ideas that (a) \macro is safest ;; before other expansions and (b) \macro is most ;; useful for porting regular LaTeX to GELLMU. ;; WARNING: \Macro has had little testing. Use with ;; extreme caution; it's hard to forsee how things ;; will look after the other substitutions. ;; ;; * Added code to control coding-system-for-write ;; without query when noninteractive ;; ;; * Added gellmu-autoclose-list; for these ;; names write a closetag at the end of an aolist ;; unless the author has already done so. Note that ;; an author endtag must follow the aolist without ;; whitespace if the name is on this list. ;; ;; 5-Jan-2001 * Activated public variable gellmu-parb-hold -- ;; list of name strings for "parb" blocking under ;; "advanced gellmu" (==> gellmu-regular-sgml false) ;; ;; * Greatly changed the function of \macro. ;; The old functionality is that of \newcommand ;; without arguments. New: whatever is in the ;; name field is the name, with or without a ;; leading backslash. The name can be anything. ;; At an invocation site a `;' immediately following ;; the macro name terminates the invocation; a ;; semi-colon used this way is discarded. ;; Use with extreme caution. If questions arise, ;; use the "expansions" exit. ;; ;; * Changed the order of macro processing to: ;; (1) \mathsym, (2) \newcommand, (3) \macro ;; ;; * Greatly widened gellmu-command-regexp to ;; to accommodate non alphanumeric command ;; names. (Name discipline will be imposed by ;; by your validating parser.) ;; ;; 1-Dec-2000 * Fixed bug in macro expansions: was not using ;; regexp-quote on names when expanding; this was ;; detected when a name contained '+' which is ;; special for Elisp regexps. ;; ;; * Fixed aolist bug: a command with a sole option ;; was getting an automatic endtag. ;; ;; * If gellmu-verbatim-clean is set, then the ;; routine gellmu-clean-verbatim is used to ;; to convert *completely literal* input ;; to a name-protected "verblist" (item = "nln") ;; -- not the past verbatim and not the present ;; default. ;; ;; * Automated manmac-like verbatim handling added. ;; Usage is NOT recommended for new documents but ;; may be useful for porting legacy documents. ;; Depends on the variables ;; gellmu-manmac-bar-name and ;; gellmu-manmac-literal ;; which are "" and nil, respectively, by default. ;; ;; * Provided automated conversion of balanced ;; `` ... '' to \quophrase{ ... } or to ;; the tag represented by the variable ;; gellmu-quophrase-name when not set to "". ;; Likewise for ` ... ' when ;; gellmu-squophrase-name is not "" (the default). ;; ;; * Provided a variable gellmu-expansions-only ;; as a flag to gellmu-trans for exiting after ;; writing a GELLMU source file (with suffix ;; the value of gellmu-expansions-suffix) after ;; washing, removing comments, and expanding all ;; of the macro pseudocommands. gellmu-trans ;; on this source should yield output identical ;; to that obtained from the original source ;; but for the value of the stem attribute. ;; * Divided the "cleanse" section into "wash" ;; and "cleanse" and moved macro expansions ;; in between the two. ;; * Attribute "stem" (value of gellmu-stem-name) ;; automatically written on root element to ;; facilitate naming of aux files by others ;; * "macro" and "newcommand" changed to allow. ;; any char other than "\" in the macro name. ;; * Provision of meta-command \mathsym (value ;; of gellmu-mathsym-name) and variables ;; gellmu-mathsym-wrapper, which surrounds ;; every invocation, and gellmu-mathsym-tag ;; which writes meta-info in the output. ;; 0.6.7 -> 0.6.8: ;; 9-Sep-2000 * Unified escapes for "basic" and "advanced": ;; 1. '\' <--- "\\" (deprecated in "advanced" GELLMU ;; since "\\" gives: "brk0" = "taburow" if in ;; "tabular", "brk" = newline if followed by ;; white space, or '\' otherwise, with all of ;; this usage not recommended in "advanced") ;; 2. '{' <-- "\{" ;; 3. '}' <-- "\}" ;; * Clean up of "basic" GELLMU handling after ;; a shakedown on docs prepared for Sebastian ;; Rahtz's version of the TEI.2 document type ;; * Newcommand with arguments; when used without ;; args, slightly more expensive than simple ;; macros. These can be mixed and matched. ;; See gellmu-newcommand-name. Should ;; gellmu-macro-name be purged from this code? ;; * Simple macros (without arguments); see ;; gellmu-macro-name. ;; * Cleaned up some error messages ;; * Enforcement of gellmu-xml-strict ;; ;; 0.6.6 -> 0.6.7: * Key-based handling of "" ;; 16-Aug-2000 * Handling of internal declaration subset and ;; SGML entity references in the standard SGML ;; notation, i.e., "&foo;" ;; * Plans for delayed internal declaration subset ;; e.g., in XML made from direct SGML output ;; * Basic GELLMU: switches that make it possible to ;; edit directly for any SGML or XML using only ;; basic LaTeX-like syntax (but not the default ;; behavior, which still supports many other LaTeX- ;; like features. With *basic* GELLMU a LaTeX-like ;; command option is used only for attributes, and ;; the leading ':' is optional. ;; * Emulation of LaTeX's tabular (lrc only) ;; Now writing "brk0" instead of "brk" in regular ;; GELLMU for "\\", if followed by white space ;; so that it can be used dually for "brk" and ;; for tabular's "taburow". ;; Now writing "tabucell" for "&" if followed by ;; white space; "&" otherwise has SGML entity ;; meaning. ;; * Many new variables, some not used yet. ;; ;; ;; 0.6.5 -> 0.6.6: ;; 13-Jul-2000 ;; The new variables may be set in a batch ;; file that launches gellmu-trans non-interactively ;; There is a good bit of control of document ;; type issues in GELLMU source. The option to ;; \documenttype, if present, now serves as a ;; key to gellmu-doctype-info. If there is no ;; option, the program will seek the key for the ;; document's root element name, i. e., the argument ;; of \documenttype, in the variable ;; gellmu-doctype-keylist. Thus, for each root name ;; there can be a preferred DOCTYPE. ;; ;; Provided variables gellmu-doctype-keylist, ;; gellmu-doctype-info, gellmu-xml-introducer, ;; and changed the former gellmu-doctype to ;; gellmu-doctype-root-element. ;; ;; 0.6.4 -> 0.6.5: ;; 29-Jun-2000 When gellmu-regular-sgml is true and, therefore, ;; the only legitimate command option is the [: ...] ;; for an attribute list, make the ':' redundant. ;; ;; Provided different rules for escaped use of '\', ;; '{', '}', '&', '%', ... in source for regular-sgml. ;; ;; Provided string gellmu-sgml-emptytag-close ;; with default value "/>" which can be changed ;; to ">" for classical SGML. ;; ;; Provided gellmu-regular-sgml to block most ;; LaTeX emulation beyond basic syntax. ;; ;; When first arg/opt is an option inside which ;; the first char is ':', the rest of the option ;; content is inserted inside the command's ;; open tag. For advanced GELLMU one ;; needs to watch what characters other than ;; 0-9A-Za-z are used in attribute values since ;; by default most other characters are made into ;; empty elements, which are not legal in attribute ;; values. Thus, for example, without regular-sgml ;; urls should not be attribute values. For this ;; reason such things that normally would be ;; attributes in the SGML world are provided as ;; command arguments or options for advanced ;; GELLMU. ;; ;; Cleaned up long strings so that this file has ;; width at most 79. ;; ;; 0.6.3 -> 0.6.4: ;; 16-Dec-1999 Changed tagging for "\foo;" from "". This has a small advantage ;; when the tag is not recognized by "nsgmls": ;; it is parsed as empty. ;; ;; Corresponding changes to gellmu-parb-regexp and ;; parb handling. ;; ;; Added code for "\-", "\/", "\,", and "\ ". ;; ;; 0.6.2 -> 0.6.3: ;; 26-Oct-1999 Small changes in gellmu-parb-regexp ;; ;; 0.6.1 -> 0.6.2: Changed incorrect loop re-entrance in code ;; 03-Aug-1999 for \begin ... \end to gellmu-tmp-pos rather ;; than gellmu-loop-pos. ;; ;; Eliminated uncontrolled variable names and ;; replaced some fixed command names with variable ;; ones. ;; ;; Cleaned up batch-mode terminal output. ;; ;; Added about a dozen user variables. See the ;; list gellmu-public-vars and conditionals based ;; on them including: ;; * gellmu-latex-body is true when gellmu-body-name ;; is found and gellmu-no-latex is not set ;; * $-toggle math zones disabled and $ is ordinary ;; if gellmu-no-latex is set ;; * blank lines are not replaced by parb's when ;; gellmu-latex-body is false ;; ;; 0.6.0 -> 0.6.1: Removed code for automatic insertion of ;; 17-Jul-1999 "preamble" tags. (Should not cause any ;; breakage with current dtd.) ;; ;; 0.5.5 -> 0.6.0: Error corrections ;; 02-Jun-1999 ;; ;; 0.5.4 -> 0.5.5: Enabled batch use: ;; 11-Oct-1998 emacs -batch -l gellmu -f gellmu-trans myfile.glm ;; ;; 0.5.3 -> 0.5.4: Cleaned up "parb" relative to new comment code ;; 11-Oct-1998 ;; ;; 0.5.2 -> 0.5.3: 1) Added 4 names to parb-hold ;; 09-Oct-1998 2) Change handling of comments before "doctype" ;; 3) Don't write "" after "" ;; 4) Write "\amptd;" for "&", not the closetag ;; ;; 0.5.1 -> 0.5.2: Comment handling revised ;; 24-Sept-1998 ;; ;; 0.5 -> 0.5.1: Light housekeeping ;; 08-Sept-1998 ;; ;; 0.5 = 0.5.0: 28-Jul-1998 (defvar gellmu-public-vars () "List of names of variables that the user may set with \"M-x set-variable\"" ) (defvar gellmu-no-latex nil "*No LaTeX emulation if true. Required for SGML attribute support. Does NOT turn off the use of blank lines in gellmu-body-name to generate gellmu-parb-name tags. (Probably it should.)" ) (add-to-list 'gellmu-public-vars "gellmu-no-latex") (defvar gellmu-no-parb nil "*Treat blank lines as miscellaneous white space if true." ) (add-to-list 'gellmu-public-vars "gellmu-no-parb") (defvar gellmu-input-mode-command "latex-mode" "*Command to invoke emacs mode for input LaTeX-like markup. (Convenience)" ) (add-to-list 'gellmu-public-vars "gellmu-input-mode-command") (defvar gellmu-input-suffix-regexp "\\.glm" "*Regexp string form of file suffix to indicate a GELLMU document." ) (add-to-list 'gellmu-public-vars "gellmu-input-suffix-regexp") (defvar gellmu-dtd-name "unknown" "*System id name of the SGML DTD for use with \"SYSTEM\" in the document type declaration. This is over-ridden by information in the variable gellmu-doctype-info." ) (add-to-list 'gellmu-public-vars "gellmu-dtd-name") (defvar gellmu-output-suffix ".sgml" "*String for file suffix of GELLMU output." ) (add-to-list 'gellmu-public-vars "gellmu-output-suffix") (defvar gellmu-preamble-tag "" "*Optional name of document preamble element, if any, for the target SGML; 'preamble' is correct for the didactic LaTeX-like \"gellmu.dtd\"." ) (add-to-list 'gellmu-public-vars "gellmu-preamble-tag") (defvar gellmu-body-name "document" "*Name of document body used in the current document; 'document' is the default (originating with LaTeX habit). Meaningless unless gellmu-latex-body is true. Required for auto-generation of parb-tags from blank lines in source. Also required for auto-generation of sy0 tags around math symbols declared before the beginning of the zone called gellmu-body-name." ) (add-to-list 'gellmu-public-vars "gellmu-body-name") (defvar gellmu-parb-name "parb" "*Name of the tag auto-generated here for each sequence of blank lines in document body where the name of the body is the value of gellmu-body-name. Meaningful only if gellmu-latex-body is true. See the list of tag names before which blank lines do not generate a parb tag in the value of the variable gellmu-parb-hold. Not effective if gellmu-no-parb is true." ) (add-to-list 'gellmu-public-vars "gellmu-parb-name") (defvar gellmu-body-tag "" "*Correct name of document body for the target SGML; 'body' is correct for the skeletal LaTeX-like \"gellmu.dtd\"." ) (add-to-list 'gellmu-public-vars "gellmu-body-tag") (defvar gellmu-dollarmath-name "tmath" "*Name of the command used for '$'-delimited inline math zones. This use of the character '$' does not pertain if gellmu-no-latex is true.") (add-to-list 'gellmu-public-vars "gellmu-dollarmath-name") (defvar gellmu-inlinemath-name "math" "*Name of the command used for inline math zones when delimited by '\(' and ')'.") (add-to-list 'gellmu-public-vars "gellmu-inlinemath-name") (defvar gellmu-displaymath-name "displaymath" "*Name of the command used for math displays when delimited by '\[' and '\]'.") (add-to-list 'gellmu-public-vars "gellmu-displaymath-name") (defvar gellmu-math-zones '(gellmu-dollarmath-name gellmu-inlinemath-name gellmu-displaymath-name "equation" "eqnarray" "eqnarray*") "*List of commands representing zones considered as under math mode." ) (add-to-list 'gellmu-public-vars "gellmu-math-zones") (defvar gellmu-no-terminal-output t "*No nominal terminal output in batch mode (except banner) if true. Use false for debugging. " ) (add-to-list 'gellmu-public-vars "gellmu-no-terminal-output") (defvar gellmu-no-diagnostic-output t "*Provide diagnostic output." ) (add-to-list 'gellmu-public-vars "gellmu-no-diagnostic-output") (defvar gellmu-debug-id "" "*String for location in this program to bail out for debugging" ) (add-to-list 'gellmu-public-vars "gellmu-debug-id") (defvar gellmu-no-auto-nbs nil "*Turn off the automatic replacement of \"~\" with gellmu-nbs-repn" ) (add-to-list 'gellmu-public-vars "gellmu-no-auto-nbs") (defvar gellmu-nbs-repn "\\nbs;" "*String value used to replace \"~\" provided gellmu-no-auto-nbs is nil" ) (add-to-list 'gellmu-public-vars "gellmu-nbs-repn") (defvar gellmu-no-auto-sol nil "*Turn off the automatic replacement of \"/\" with " ) (add-to-list 'gellmu-public-vars "gellmu-no-auto-sol") (defvar gellmu-straight-sgml nil "*Set this for regular SGML with no LaTeX-like features. Implies gellmu-regular-sgml. Default value is nil." ) (add-to-list 'gellmu-public-vars "gellmu-straight-sgml") (defvar gellmu-regular-sgml nil "*Set this for regular SGML with few LaTeX-like features. Blank lines as paragraphs are allowed inside gellmu-body-name, provided that GELLMU-style use of that feature is enabled (usually with an appropriate entry in gellmu-doctype-keylist). Default value is nil." ) (add-to-list 'gellmu-public-vars "gellmu-regular-sgml") (defvar gellmu-sgml-emptytag-close "/>" "*String for closing the tag to which \foo; is translated; rational choices include \"\" (modern), \"\" (classical), and \"\", the default, is correct for XML." ) (add-to-list 'gellmu-public-vars "gellmu-sgml-emptytag-close") (defvar gellmu-xml-strict nil "*Attempt to make output file a conforming xml file." ) (add-to-list 'gellmu-public-vars "gellmu-xml-strict") (defvar gellmu-xml-introducer "" "*The SGML processing instruction used to specify XML. This applies only if you are writing directly for an XML document type without an intermediate passage through SGML. If used with non-ASCII characters, even 8 bit characters under ISO-latin-1, this variable should be modified to specify an encoding according to the XML specification. For example, ''" ) (add-to-list 'gellmu-public-vars "gellmu-xml-introducer") (defvar gellmu-doctype-keylist '(("article" . ("gellmuart" "preamble" "body")) ("memo" . ("gellmumemo" "memohead" "memobody")) ("html" . ("html-5")) ("refentry" . ("solbookv2")) ("TEI.2" . ("passivetexTEI.2")) ) "*An associative list (of dotted pairs) matching document root element names with document type keys and, when in LaTeX emulation mode, i.e., gellmu-no-latex is nil, optionally preamble and body tag names" ) (add-to-list 'gellmu-public-vars "gellmu-doctype-keylist") (defvar gellmu-doctype-info '(("INTERNAL" . ("sgml")) ; internal declaration subset only ("XINTERNAL" . ("xml")) ; internal declaration subset only ("gellmuart" . ("sgml" "SYSTEM" "gellmu.dtd")) ("gellmumemo" . ("sgml" "SYSTEM" "gellmu.dtd")) ("solbookv2" . ("sgml" "PUBLIC" "-//Sun Microsystems//DTD DocBook V3.0-Based SolBook Subset V2.0//EN")) ("passivetexTEI.2" . ("xml" "SYSTEM" "tei-oucs.dtd")) ("html-4.0" . ("sgml" "PUBLIC" "-//W3C//DTD HTML 4.0 Transitional//EN")) ("html-4.01" . ("sgml" "PUBLIC" "-//W3C//DTD HTML 4.01 Transitional//EN")) ("html-5" . ("sgml")) ("html-frames" . ("sgml" "PUBLIC" "-//W3C//DTD HTML 4.01 Frameset//EN")) ("xhtml-1.0" . ("xml" "PUBLIC" "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" "UTF-8" "xmlns=\"http://www.w3.org/1999/xhtml\"" ) ) ("xhtml-1.0s" . ("xml" "PUBLIC" "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" "UTF-8" "xmlns=\"http://www.w3.org/1999/xhtml\"" ) ) ("mmlxhtml-11-20". ("xml" "PUBLIC" "-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN" "http://www.w3.org/TR/MathML2/dtd/xhtml-math11-f.dtd" "UTF-8" "xmlns=\"http://www.w3.org/1999/xhtml\"" ) ) ("mathml-altheim" . ("xml" "PUBLIC" "-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN" "mathml.dtd" ; for validation use this as a catalog "front" "UTF-8" "xmlns=\"http://www.w3.org/1999/xhtml\"" ) ) ("docbook-xml-4.1.2" . ("xml" "PUBLIC" "-//OASIS//DTD DocBook XML V4.1.2//EN" "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" "UTF-8" ) ) ) "*An associative list matching document type keys with lists of document type information in which the first element is \"sgml\" or \"xml\". As to the remainder of the list: The first element is \"SYSTEM\" or \"PUBLIC\". If the first element is \"SYSTEM\", then the second element is a system identifier, and an optional third element is a content-encoding specifier. If the first element is \"PUBLIC\", then the second element is a formal public identifier, an optional third element, which may be an empty string, is a uniform resource indicator or system identifier, an optional fourth element is a content-encoding specifier, and an optional fifth element is a string of name=value attribute settings for the root element." ) (add-to-list 'gellmu-public-vars "gellmu-doctype-info") (defvar gellmu-tab-amp "&" "*String used in GELLMU source with gellmu-regular-sgml false to emulate a LaTeX-like tabular cell divider. Unlike with LaTeX itself this is not effective unless followed by white space since otherwise, at least for the case of its default value (\"&\"), this character is expected to have another use. For its default value the other use is for SGML entity introduction. User changes of this variable can be dangerous." ) (add-to-list 'gellmu-public-vars "gellmu-tab-amp") (defvar gellmu-tab-cell "tabampcell " "*Name used with gellmu-regular-sgml false to replace occurrences of gellmu-tab-amp-re." ) (add-to-list 'gellmu-public-vars "gellmu-tab-cell") (defvar gellmu-sgml-entity-name "entity" "*Name used in GELLMU source for an SGML entity definition in the document's internal declaration subset. Note: in the value field the characters '\\', '{', '}', and '%' must be escaped." ) (add-to-list 'gellmu-public-vars "gellmu-sgml-entity-name") (defvar gellmu-sgml-notation-name "notation" "*Name used in GELLMU source for an SGML notation declaration in the document's internal declaration subset" ) (add-to-list 'gellmu-public-vars "gellmu-sgml-notation-name") (defvar gellmu-sgml-attlist-name "attlist" "*Name used in GELLMU source for an SGML attribute list definition in the document's internal declaration subset" ) (add-to-list 'gellmu-public-vars "gellmu-sgml-attlist-name") (defvar gellmu-sgml-element-name "element" "*Name used in GELLMU source for an SGML element type definition in the document's internal declaration subset" ) (add-to-list 'gellmu-public-vars "gellmu-sgml-element-name") (defvar gellmu-macro-name "macro" "*Name of two argument command for basic (early) macro substitution. Use with caution. These macros need not necessarily begin with \"\\\": in that case use with extreme caution." ) (add-to-list 'gellmu-public-vars "gellmu-macro-name") (defvar gellmu-late-macro-name "Macro" "*Name of two argument command for macro substitutions that are performed after all other expansions, i.e., after regular macro, mathsym and newcommand. Use with very extreme caution." ) (add-to-list 'gellmu-public-vars "gellmu-late-macro-name") (defvar gellmu-newcommand-name "newcommand" "*Name of two option, two argument command for macro substitution with arguments" ) (add-to-list 'gellmu-public-vars "gellmu-newcommand-name") (defvar gellmu-mathsym-name "mathsym" "*Name of the GELLMU command used for the declaration of math symbols. Inside gellmu-body-name each invocation of \foo for a declared symbol name \"foo\" (called the key) leads to a macro expansion that is automatically wrapped in an sy0 container whose \"key\" attribute is the key and whose element content is the macro value given in the second argument. Its optional third argument is a string consisting of (name, value) pairs that are suitable for *your* local production system. Further processing of the information generated with this command is not part of the syntactic translation into SGML. The intention is that the information in the optional third argumen be semantic in nature and be handled with custom SGML processors." ) (add-to-list 'gellmu-public-vars "gellmu-mathsym-name") (defvar gellmu-mathsym-wrapper "Sym" "*Name of the wrapper generated upon each invocation of a symbol declared with gellmu-mathsym-name." ) (add-to-list 'gellmu-public-vars "gellmu-mathsym-wrapper") (defvar gellmu-mathsym-tag "mathsym" "*Name of the SGML tag written in the output at the location of a gellmu-mathsym-name command in the source. Its contents, which may not contain markup, consist minimally of the name of the declared symbol. Other contents, separated by white space from the name, consist of the list of (name, value) pairs, if any, provided in the optional third argument. The tag must, of course, be defined in the SGML document type. (The GELLMU macro expansion given by the second argument of gellmu-mathsym-name is not recorded inside gellmu-mathsym-tag.)" ) (add-to-list 'gellmu-public-vars "gellmu-mathsym-tag") (defvar gellmu-symkey-name "key" "*Name of the sy0 attribute generated automatically for each sy0 wrapping of the macro expansion of each invocation of a math symbol declared with gellmu-mathsym-name. Its value is the symbol's name. It can be the basis for searching the occurrences of a declared symbol with a downstream processor." ) (add-to-list 'gellmu-public-vars "gellmu-symkey-name") (defvar gellmu-expansions-only nil "*Flag for non-debugging exit from gellmu-trans." ) (add-to-list 'gellmu-public-vars "gellmu-expansions-only") (defvar gellmu-expansions-suffix "E.glm" "*Suffix for file written following all of the various macro expansions if a non-debug exit is ordered by the user through setting the logical gellmu-expansions-only." ) (add-to-list 'gellmu-public-vars "gellmu-expansions-suffix") (defvar gellmu-quophrase-name "quophrase" "*Name of tag for LaTeX-like ``quoted phrases''. Setting its value to the empty string disables this feature." ) (add-to-list 'gellmu-public-vars "gellmu-quophrase-name") (defvar gellmu-squophrase-name "" "*Name of tag for LaTeX-like `singly-quoted phrases'. Setting its value to the empty string disables this feature." ) (add-to-list 'gellmu-public-vars "gellmu-squophrase-name") (defvar gellmu-manmac-bar-name "" "*Name of tag for manmac-like |quoted phrases|. Setting its value to the empty string disables this feature." ) (add-to-list 'gellmu-public-vars "gellmu-manmac-bar-name") (defvar gellmu-manmac-bar-attribute "" "*Name of attribute for gellmu-manmac-bar-name to hold the name of any \\foo immediately preceding a manmac-like |quote|. Setting its value to the empty string withholds the writing of this attribute." ) (add-to-list 'gellmu-public-vars "gellmu-manmac-bar-attribute") (defvar gellmu-manmac-literal nil "*Logical to indicate that all characters in manmac-like areas should be treated as literal except for the area delimiter '|'") (add-to-list 'gellmu-public-vars "gellmu-manmac-literal") (defvar gellmu-verbatim-clean nil "*Logical to indicate that gellmu-trans should treat all characters inside /^\\begin{verbatim}$/ ... /^\\end{verbatim}$/ as literal and the contents set as \"verblist\" rather than as pre-historic \"verbatim\" (which still remains in the GELLMU didactic DTD for \"article\"). Note that there is no standard name in SGML for verbatim contents." ) (add-to-list 'gellmu-public-vars "gellmu-verbatim-clean") (defvar gellmu-sgml-default-coding 'utf-8 "*Name of the file coding to be used for saving the SGML output when non interactive and the local value of the variable buffer-file-coding-system in the source buffer is nil. Otherwise that value is used unless coding-system-for-write is non nil. (One's SGML parser must be tuned for the file coding under which the SGML output is delivered.) ") (add-to-list 'gellmu-public-vars "gellmu-sgml-default-coding") (defvar gellmu-autoclose-list '( "section" "subsection" "subsubsection" "paragraph" "subparagraph" "anch" "frac" "binom" "cite" "documentclass" "ent" "sqrt" "ftanch" "vect" "mscript" "setOf" "overset" "underset" ) "*For advanced gellmu. List of names of commands that take at least one non-attribute option or at least one tagged argument for which the automatic generation of closetags is desired when closure is not present in GELLMU source." ) (add-to-list 'gellmu-public-vars "gellmu-autoclose-list") (defvar gellmu-apostrophe-tag "\\apos;" "*Markup string used for an apostrophe found in the course of \"quophrase\" and \"squophrase\" handling." ) (add-to-list 'gellmu-public-vars "gellmu-apostrophe-tag") (defvar gellmu-parb-hold '( "article" "memo" "Section" "section" "Subsection" "subsection" "Subsubsection" "subsubsection" "Paragraph" "paragraph" "Subparagraph" "subparagraph" "latexcommand" "abstract" "document" "body" "legalnotice" "tableofcontents" "TableOfContents" "maketitle" "par" "verbatim" "hdr" "subhdr" "subsubhdr" "suphdr" "supsuphdr" "supsupsuphdr" "hdrc" "subhdrc" "subsubhdrc" "suphdrc" "supsuphdrc" "supsupsuphdrc" "hrule" "enumerate" "itemize" "description" "defnlist" "menu" "Menu" "parlist" "booklist" "tablist" "comment" "assertion" "item" "term" "desc" "bibitem" "vbibitem" "bibentry" "bibbody" "bibhead" "biblabel" "bibkey" "tabular" "table" "Table" "tableb" "tablec" "tablech" "quote" "quotation" "bigskip" "medskip" "smallskip" "thebibliography" ) "*List of regexps for command names before which a sequence of blank lines in document body will NOT be considered to begin a new \"parb\" paragraph. It should be noted that the presence or absence of a name here may or may not be consistent with the provisions of a DTD. The \"parb\" stuff may be turned off by setting the variable gellmu-no-parb true. See the comments in the source code for this package (gellmu.el)." ) (add-to-list 'gellmu-public-vars "gellmu-parb-hold") (defvar gellmu-parb-everywhere nil "*Unless gellmu-no-parb is set, provides parb handling throughout" ) (add-to-list 'gellmu-public-vars "gellmu-parb-everywhere") (defvar gellmu-doc-fragment nil "*True if source file is a fragment of a larger document" ) (add-to-list 'gellmu-public-vars "gellmu-doc-fragment") (defvar gellmu-procinst-name "ProcInst" "*Name of the command whose contents become those of an SGML/XML processing instruction." ) (add-to-list 'gellmu-public-vars "gellmu-procinst-name") (defvar gellmu-hold-xml-introducer nil "*Blocks the writing of an XML declaration at the top of the document if true. Provided for the case of XHTML documents that are meant to be backward compatible with old HTML user agents. Defaults to nil except for the gellmu-xhtml function call." ) (add-to-list 'gellmu-public-vars "gellmu-hold-xml-introducer") ;; ;; end of GELLMU user-available public variables ;; ;; For tab-amp-tail the next line picks out the right things interactively: ;; (re-search-forward "[\\ \\\t\\\n]" nil t) ;; (defvar gellmu-tab-amp-tail "\\( \\|\\n\\)" (defvar gellmu-tab-amp-tail "\\( \\|\\\t\\|\\\n\\)" "Regexp for string used in GELLMU source with gellmu-regular-sgml false to follow a LaTeX-like tabular cell divider. Since this involves a newline user-level change is not provided. Change could risk spoiling newline alignment between GELLMU source and SGML output." ) (defvar gellmu-parb-regexp-name-subexp "") (setq gellmu-parb-regexp-name-subexp (let (sl nl) (setq sl gellmu-parb-hold) (setq nl "") (if (< 0 (length sl))(progn (setq nl (car sl))(setq sl (cdr sl)))) (while (< 0 (length sl)) (setq nl (concat nl "\\|" (car sl))) (setq sl (cdr sl)) ) nl ) ) (defvar gellmu-parb-regexp (concat "\n" "\\(\\( \\|\t\\|\n\\|\\|\\|\\|\\)*\\)" ;; \1, \2 "\n" "\\([ \t]*\\)" ;; \3 "<" "\\(/\\)?" ;; \4 "\\(" ;; beginning of \5 gellmu-parb-regexp-name-subexp "\\)" ;; end of \5 "\\([ >/]\\)" ;; new non-embedded \6 ) "*An RE for the list of parb exceptional tag names; see gellmu-parb-name. Setting this interactively could be very risky. For that an interactive interface should be provided (in the code) to build this RE." ) ;;;; WARNING: Alter gellmu-parb-regexp only with extreme care ;;;; Note that in emacs's "Emacs-Lisp" mode ;;;; forward- and backward- sexp can be used to check the sanity of ;;;; (1) the argument list of concat ;;;; (2) the marked regular sub-expressions (across concat args) ;;;; Note: with this construction each name might as well have an ;;;; explicit wild card at its end, i.e., the names are initial ;;;; segments (except for the comment names) (defvar gellmu-parb-regexp-old ;; now replaced by new gellmu-parb-regexp (concat "\n" "\\(\\( \\|\t\\|\n\\|\\|\\|\\|\\)*\\)" ;; \1, \2 "\n" "\\([ \t]*\\)" ;; \3 "<" "\\(/\\)?" ;; \4 "\\(" ;; beginning of \5 "\\([Ss]ub\\)*[Ss]ection" ;; \6 "\\|abstract\\|document\\|body\\|maketitle\\|par" "\\|item\\|hdr\\|subhdr\\|subsubhdr\\|suphdr\\|supsuphdr\\|supsupsuphdr" "\\|hrule\\|enumer\\|quote\\|quotation\\|table\\|Tabular\\|Table" "\\|bigskip\\|medskip\\|smallskip\\|verbatim\\|defnlist\\|term\\|desc" "\\|eqnarray\\|article\\|memo\\|menu\\|legalnotice\\|parlist" "\\|thebibliography\\|bibitem\\|vbibitem\\|bibentry\\|bibliography" "\\|bibhead\\|bibbody\\|biblabel\\|bibkey" "\\|description\\|booklist\\|tablist\\|comment\\|latexcommand" "\\)" ;; end of \5 ) "*An RE for the list of parb exceptional tag names; see gellmu-parb-name. Setting this interactively could be very risky. For that an interactive interface should be provided (in the code) to build this RE." ) (defvar gellmu-autoclose-regexp nil) (setq gellmu-autoclose-regexp "") (setq gellmu-autoclose-regexp (let (acl acre) (setq acl gellmu-autoclose-list) (setq acre "") (if (< 0 (length acl)) (progn (setq acre "^\\(") (setq acre (concat acre (car acl))) (setq acl (cdr acl)) (while (< 0 (length acl)) (setq acre (concat acre "\\|" (car acl))) (setq acl (cdr acl)) ) (setq acre (concat acre "\\)$")) ) ) acre ) ) (if (string-equal gellmu-autoclose-regexp "") (setq gellmu-autoclose-regexp nil) ) (defvar gellmu-next-open-char 0 "Gellmu: the next forward open-char location" ) (defvar gellmu-next-close-char 0 "Gellmu: the close-char location, if any, matching gellmu-next-open-char" ) (defvar gellmu-previous-open-char 0 "Gellmu: the previous open-char location" ) (defvar gellmu-previous-close-char 0 "Gellmu: the close-char location, if any, matching gellmu-previous-open-char" ) (defvar gellmu-balance-pair-base 0 "Location of point when gellmu-balance-pair-forward is called" ) (defvar gellmu-latex-body nil "Logical for the LaTeX-like occurrence of a \\begin{document}, which then must be followed by a \\end{document}. Not effective when gellmu-no-latex is set." ) (defvar gellmu-misc-re-a (concat "\\(\\( \\|\n\\|\\|\\)*\\)\n\n" "\\(\\( \\|\n\\|\\|\\)*\\)" ) ) (let ((sufoffset nil)) (setq sufoffset (string-match gellmu-input-suffix-regexp (buffer-name))) (if sufoffset (progn (fset 'gellmu-input-mode-command (intern gellmu-input-mode-command)) (gellmu-input-mode-command) )()) ) (defmacro gellmu-char-after (loc) ; Unused: should it be a defsubst if used? "Returns 0 if ordinary \"char-after\" returns nil, which is fine so long as we do not use the nul character. (Unused by gellmu?)" (let ((cav nil))(setq cav (char-after loc))(if cav cav 0)) ) (defsubst gellmu-message (gstring) "Simple message routine for strings prepared with \"format\" that is switched according to whether or not the process is interactive. A newline is added to the string argument so that the string argument is compatible with one constructed for the function \"error\". " (if noninteractive (send-string-to-terminal (concat gstring "\n")) (print gstring) ) ) (defsubst gellmu-dbmessage (gstring) "Simple debug message routine for strings prepared with \"format\" that is switched according to whether or not the process is interactive. A newline is added to the string argument so that the string argument is compatible with one constructed for the function \"error\". " (what-line) (if noninteractive (send-string-to-terminal (concat gstring "\n")) (print gstring) ) ) (defsubst gellmu-render-literal (barstr) "Make the argument string safe for GELLMU source markup under the assumption that it contains no markup. Characters affected are: \ { } ^ _ ~ # $ % & ` ' . " (let ( (i 0) ) (while (string-match "\\\\" barstr i) (setq barstr (replace-match "\\bsl;" t t barstr)) (setq i (match-end 0)) ) (while (string-match "{" barstr) (setq barstr (replace-match "\\lbr;" t t barstr)) ) (while (string-match "}" barstr) (setq barstr (replace-match "\\rbr;" t t barstr)) ) (while (string-match " " barstr) (setq barstr (replace-match "\\spc;" t t barstr)) ) (while (string-match "\\^" barstr) (setq barstr (replace-match "\\crt;" t t barstr)) ) (while (string-match "_" barstr) (setq barstr (replace-match "\\und;" t t barstr)) ) (while (string-match "~" barstr) (setq barstr (replace-match "\\tld;" t t barstr)) ) (while (string-match "#" barstr) (setq barstr (replace-match "\\hsh;" t t barstr)) ) (while (string-match "\\$" barstr) (setq barstr (replace-match "\\dol;" t t barstr)) ) (while (string-match "%" barstr) (setq barstr (replace-match "\\pct;" t t barstr)) ) (while (string-match "&" barstr) (setq barstr (replace-match "\\amp;" t t barstr)) ) (while (string-match "`" barstr) (setq barstr (replace-match "\\lsq;" t t barstr)) ) (while (string-match "'" barstr) (setq barstr (replace-match "\\rsq;" t t barstr)) ) (while (string-match "\\\[" barstr) (setq barstr (replace-match "\\lsb;" t t barstr)) ) (while (string-match "\\]" barstr) (setq barstr (replace-match "\\rsb;" t t barstr)) ) (while (string-match "(" barstr) (setq barstr (replace-match "\\lpr;" t t barstr)) ) (while (string-match ")" barstr) (setq barstr (replace-match "\\rpr;" t t barstr)) ) (while (string-match "\"" barstr) (setq barstr (replace-match "\\quo;" t t barstr)) ) (while (string-match "\\*" barstr) (setq barstr (replace-match "\\ast;" t t barstr)) ) (while (string-match "@" barstr) (setq barstr (replace-match "\\atc;" t t barstr)) ) (while (string-match "-" barstr) (setq barstr (replace-match "\\hyp;" t t barstr)) ) (while (string-match "\\+" barstr) (setq barstr (replace-match "\\plu;" t t barstr)) ) (while (string-match "=" barstr) (setq barstr (replace-match "\\eqc;" t t barstr)) ) (while (string-match "<" barstr) (setq barstr (replace-match "\\ltc;" t t barstr)) ) (while (string-match ">" barstr) (setq barstr (replace-match "\\gtc;" t t barstr)) ) (while (string-match ":" barstr) (setq barstr (replace-match "\\cln;" t t barstr)) ) (while (string-match "/" barstr) (setq barstr (replace-match "\\sol;" t t barstr)) ) (while (string-match "\\." barstr) (setq barstr (replace-match "\\per;" t t barstr)) ) (while (string-match "\\?" barstr) (setq barstr (replace-match "\\qum;" t t barstr)) ) (while (string-match "!" barstr) (setq barstr (replace-match "\\exc;" t t barstr)) ) (while (string-match "," barstr) (setq barstr (replace-match "\\cma;" t t barstr)) ) (while (string-match "|" barstr) (setq barstr (replace-match "\\vbr;" t t barstr)) ) ; probably do not need to do the other non-alphanumerics EXCEPT ; for those that get later treatment with (not gellmu-regular-sgml) ; currently: * @ - + = < > / . ? ! | ; but not: " : , ; ) barstr ) (defsubst gellmu-clean-verbatim (vbstr) "Make the argument string safe for GELLMU source markup under the assumption that it contains no markup. Characters affected: all printable ASCII except semi-colon, i.e., ';' (for which the cost of replacement by '\\scl;' is probably worth more than the benefit). " (let (gvci gvcl fvci fstr tvci tstr) (progn ; code for cleaning "\" must be first (setq gvci 0) (while (string-match "\\\\" vbstr gvci) (setq vbstr (replace-match "\\bsl;" t t vbstr)) (setq gvci (+ (match-end 0) 4)) ) ) (while (string-match "{" vbstr) (setq vbstr (replace-match "\\lbr;" t t vbstr)) ) (while (string-match "}" vbstr) (setq vbstr (replace-match "\\rbr;" t t vbstr)) ) (progn ; "\n" -- must be preceded by code for "{" and "}" (setq gvci 0) (setq gvcl 0) (setq fstr "\n\\nln{") (setq fvci 5) ; length of fstr - 1 (setq tstr "}\n\\nln{") (setq tvci 6) ; length of tstr - 1 (while (string-match "\n" vbstr gvci) (if (= 0 gvcl) (progn (setq vbstr (replace-match fstr t t vbstr)) (setq gvci (+ (match-end 0) fvci)) ) (progn (setq vbstr (replace-match tstr t t vbstr)) (setq gvci (+ (match-end 0) tvci)) ) ) (setq gvcl (1+ gvcl)) ) (setq vbstr (concat vbstr "}")) ) (while (string-match " " vbstr) (setq vbstr (replace-match "\\spc;" t t vbstr)) ) (while (string-match "\\^" vbstr) (setq vbstr (replace-match "\\crt;" t t vbstr)) ) (while (string-match "_" vbstr) (setq vbstr (replace-match "\\und;" t t vbstr)) ) (while (string-match "~" vbstr) (setq vbstr (replace-match "\\tld;" t t vbstr)) ) (while (string-match "#" vbstr) (setq vbstr (replace-match "\\hsh;" t t vbstr)) ) (while (string-match "\\$" vbstr) (setq vbstr (replace-match "\\dol;" t t vbstr)) ) (while (string-match "%" vbstr) (setq vbstr (replace-match "\\pct;" t t vbstr)) ) (while (string-match "&" vbstr) (setq vbstr (replace-match "\\amp;" t t vbstr)) ) (while (string-match "`" vbstr) (setq vbstr (replace-match "\\lsq;" t t vbstr)) ) (while (string-match "'" vbstr) (setq vbstr (replace-match "\\rsq;" t t vbstr)) ) (while (string-match "\\\[" vbstr) (setq vbstr (replace-match "\\lsb;" t t vbstr)) ) (while (string-match "\\]" vbstr) (setq vbstr (replace-match "\\rsb;" t t vbstr)) ) (while (string-match "(" vbstr) (setq vbstr (replace-match "\\lpr;" t t vbstr)) ) (while (string-match ")" vbstr) (setq vbstr (replace-match "\\rpr;" t t vbstr)) ) (while (string-match "\"" vbstr) (setq vbstr (replace-match "\\quo;" t t vbstr)) ) (while (string-match "\\*" vbstr) (setq vbstr (replace-match "\\ast;" t t vbstr)) ) (while (string-match "@" vbstr) (setq vbstr (replace-match "\\atc;" t t vbstr)) ) (while (string-match "-" vbstr) (setq vbstr (replace-match "\\hyp;" t t vbstr)) ) (while (string-match "\\+" vbstr) (setq vbstr (replace-match "\\plu;" t t vbstr)) ) (while (string-match "=" vbstr) (setq vbstr (replace-match "\\eqc;" t t vbstr)) ) (while (string-match "<" vbstr) (setq vbstr (replace-match "\\ltc;" t t vbstr)) ) (while (string-match ">" vbstr) (setq vbstr (replace-match "\\gtc;" t t vbstr)) ) (while (string-match ":" vbstr) (setq vbstr (replace-match "\\cln;" t t vbstr)) ) (while (string-match "/" vbstr) (setq vbstr (replace-match "\\sol;" t t vbstr)) ) (while (string-match "\\." vbstr) (setq vbstr (replace-match "\\per;" t t vbstr)) ) (while (string-match "\\?" vbstr) (setq vbstr (replace-match "\\qum;" t t vbstr)) ) (while (string-match "!" vbstr) (setq vbstr (replace-match "\\exc;" t t vbstr)) ) (while (string-match "," vbstr) (setq vbstr (replace-match "\\cma;" t t vbstr)) ) (while (string-match "|" vbstr) (setq vbstr (replace-match "\\vbr;" t t vbstr)) ) ) vbstr ) ;; The principal function (defun gellmu-trans () "GELLMU syntactic translator: principal function" (interactive) ; ; debug-id "early" (defvar glm-err-str "" "Auxiliary string for diagnostic messages.") (defvar gellmu-debug-garbage "" "Auxiliary string for debugging.") (defvar gellmu-loopct 0 "Internal position holder") (defvar gellmu-tmp-il-loc 0 "Internal location holder") (defvar gellmu-file-arg "" "Filename specified in batch operation") (defvar gellmu-full-filename "" "Expanded version of batch-specified filename" ) (defvar gellmu-file-name "") (defvar gellmu-stem-name "" "Filename less suffix") (defvar gellmu-source-coding nil "Value, if any, found for buffer-file-coding-system in the source buffer or otherwise nil. " ) (setq gellmu-source-coding nil) ; keep fresh (defvar gellmu-tab-amp-re (concat gellmu-tab-amp gellmu-tab-amp-tail) "Regexp formed by concatenating the user variable gellmu-tab-amp and the load-time variable gellmu-tab-amp-tail." ) ;; Is there a command line to handle? (if noninteractive ; ; emacs strips out "-batch" ; ; This next code should be altered to allow variable setting from ; ; the command line ; ; ; ; Should use something more like standard getargs, a while on ; ; the length of command-line-args, which is a list whose first ; ; member is the name of Emacs. ; ; (if (>= (length command-line-args) 6) (progn ; enough command line args (setq glm-err-str (concat "GELLMU transliterator, v. " gellmu-version ", Copyright (c) 1999-2007 William F. Hammond\n" " Released without warranty under the GNU General Public License\n" ) ) (send-string-to-terminal glm-err-str) (if (= (length command-line-args) 6) (progn ; exactly 6 command line args (setq gellmu-file-arg (car (cdr (cdr (cdr (cdr (cdr command-line-args)))))) ) (setq gellmu-full-filename (expand-file-name gellmu-file-arg) ) (access-file gellmu-full-filename "Filename not found.") (find-file gellmu-file-arg) ) ; end of case: exactly 6 command line args (let ; more than 6 command line args ((args-list (cdr command-line-args)) (this-arg "")) (while (< 0 (length args-list)) (setq this-arg (car args-list)) (setq args-list (cdr args-list)) (if (string-match "^-" this-arg) ;; skipping over "^-" arguments for now (setq args-list (cdr args-list)) (progn ; not "^-": act as if this is the file arg (setq gellmu-file-arg this-arg) (setq gellmu-full-filename (expand-file-name gellmu-file-arg) ) (access-file gellmu-full-filename "Filename not found.") (find-file gellmu-file-arg) ) ; end of file arg handling ) ; end of if string-match "^-" ) ; end of while length args list > 0 ) ; end of case: more than 6 command line args ) (setq gellmu-file-name gellmu-full-filename) ) (progn ; not enough command line args (setq glm-err-str "Gellmu: incorrect command line\n") (setq glm-err-str (concat glm-err-str "Usage: emacs -batch -l path-to-gellmu -f gellmu-trans filename\n")) (setq glm-err-str (concat glm-err-str "Number of args: %d\nArg list: %s\n")) (error glm-err-str (length command-line-args) command-line-args) ) ) ;; if noninteractive TRUE (itself an "if" on number of arguments) (progn ;; Interactive in this sexp ; ; Set gellmu-file-name (setq gellmu-file-name (buffer-name)) ) ;; if noninteractive FALSE ) ; ; Remember source file coding system, if any (if buffer-file-coding-system (setq gellmu-source-coding buffer-file-coding-system) ) ; ; Compute gellmu-stem-name (let (tstem bstem) (if (string-match "\\(^.*\\)\\(\\.\\)" gellmu-file-name) ; (setq gellmu-stem-name (match-string 1 gellmu-file-name)) ; (setq gellmu-stem-name gellmu-file-name) (setq tstem (match-string 1 gellmu-file-name)) (setq tstem gellmu-file-name) ) (setq bstem tstem) (if (string-match "^.*/\\(\[^/\]*\\)$" tstem) (setq bstem (match-string 1 tstem)) ) (setq gellmu-stem-name bstem) ) ;; Some diagnostic aids mainly for batch operation (if (and noninteractive (not gellmu-no-terminal-output)) (progn (setq glm-err-str " GELLMU filename specified: %s\n") (setq glm-err-str (concat glm-err-str " Expanded filename: %s\n")) (setq glm-err-str (concat glm-err-str " Regexp form of input suffix: %s\n")) (setq glm-err-str (concat glm-err-str " Output suffix: %s\n")) (setq glm-err-str (concat glm-err-str " DTD name: %s\n")) (send-string-to-terminal (format glm-err-str gellmu-file-arg gellmu-full-filename gellmu-input-suffix-regexp gellmu-output-suffix gellmu-dtd-name ) ) ) ; noninteractive and terminal output allowed TRUE () ; noninteractive and terminal output allowed FALSE ) ; end of if noninteractive and ... ;;;; Variables whose default values are available for tinkering by ;;;; Emacs Lisp programmers ;;;; Tinkering here can cause things to break seriously ;;;; Be very careful!!! ; gellmu-input-mode-command should be loaded and set when ; this file is loaded (defvar gellmu-output-mode-command "sgml-mode" "Command to invoke emacs mode for GELLMU output buffer." ) ; (defvar gellmu-command-regexp "[A-Za-z][0-9A-Za-z]*\\*?" (defvar gellmu-re-rng-open "[^]\\\\{} \"!@#$%^&*\(\)_+=`~;<>/?") (defvar gellmu-re-rng-close "[]") (defvar gellmu-command-regexp (concat gellmu-re-rng-open "0-9" gellmu-re-rng-close gellmu-re-rng-open "0" gellmu-re-rng-close "*" ) "Elisp string definition of regexp for matching the name of a command." ) (defvar gellmu-command-regexp-old "[^]\\\\{} \"!@#$%^&*\(\)_+=`~;<>/?0-9[][^]\\\\{} \"!@#$%^&*\(\)_+=`~;<>/?0[]*" ) (defvar gellmu-attr-regexp "[-_0-9A-Za-z:/.?@#%=+\"]" "Elisp string definition of regexp for matching a string that is allowable as the attribute list for an SGML element. Is this enforced? Note: '#' is less Gellmu-special than '_' and '%' are; to get these into input precede them with a '\\'. Unused." ) ;; *** ;;;; Internal variables below here; do not tinker with their defaults ;; *** ;; Why are so many names put into defvar namespace? ;; When an authoring task gets tough, you can run this interactively. ;; And then you can check the values of these names at the time of a ;; problem. (defvar gellmu-doctype-root-element nil "Name of the GELLMU root element of the current document or nil as declared in the document with the \\documenttype command" ) (setq gellmu-doctype-root-element nil) ; keep fresh (defvar gellmu-doctype-opt-regexp "\\(\\[[-/:%~\\ \\.0-9_A-Za-z]*\\]\\)?" "Value of the regexp for the first option of \\documenttype. Whitespace allowed here so that it can be specifically caught later. " ) (defvar gellmu-doctype-arg-regexp "{\\([A-Za-z][-\\.0-9A-Za-z]*\\)}" "Value of the regexp for the argument of \\documentype" ) (defvar gellmu-start 0 "Location of the first point in buffer beyond the GELLMU \documenttype declaration, if any , the internal declaration subset, if any, and the starttag for the root element specified with \documenttype, if any." ) (setq gellmu-start 0) ; keep fresh (defvar gellmu-internal-start 0 "The beginning of the internal declaration subset, if any." ) (setq gellmu-internal-start 0) (defvar gellmu-internal-end 0 "The beginning of the internal declaration subset, if any." ) (setq gellmu-internal-end 0) (defvar gellmu-macro-start 0 "The beginning of macro definitions, if any." ) (setq gellmu-macro-start 0) (defvar gellmu-mathsym-start 0 "The beginning of math symbol declarations, if any." ) (defvar gellmu-mathsym-start 0) (defvar gellmu-buff-name (buffer-name) "GELLMU: name of input buffer; defaults to Gellmu load time buffer") (defvar gellmu-write-buff "0-0gellmu0-0" "GELLMU: name of write buffer") (defvar gellmu-expansions-buff "0-0gellmu0-0E" "GELLMU: name of buffer for macro expansions") (defvar gellmu-element-list nil "List of all SGML non-empty element names needed for current document") (defvar gellmu-reserved '("ag0" "op0" "lg0" "sy0") "List of all reserved names in GELLMU") (defvar gellmu-tmp-pos (point-min) "GELLMU: temporary location marker for calculation and error messages") (defvar gellmu-tmp-str "" "GELLMU: temporary string for manipulation and error messages") (defvar gellmu-loop-pos "" "GELLMU: temporary location marker for loops") (defvar gellmu-dol-zone 0 "GELLMU: flag (0 or 1) for $-delimited math zone") ;; used? (setq gellmu-dol-zone 0) (defvar gellmu-dol-orig 0 "GELLMU: location of origin of last $-delimited math zone before point") (setq gellmu-dol-orig 0) (defvar gellmu-dol-maxlength 255 "GELLMU: maximum length of $-delimited math zone (for error detection)") (defvar gellmu-sc-list '( ("{" . ?\{) ("[" . ?\[) ) ) ; static ; ; Command names generated should have a first numeric "0". (defvar gellmu-st-list '( ("{" . "ag0") ("[" . "op0") ) ) ; static ; Look for the string "RISKY CODE" below involving either of the ; above names below. (defvar gellmu-com-re (concat "\\\\\\(b0\\)?\\(" gellmu-command-regexp "\\)") "Gellmu: construction RE, \\ + \\1 + \\2; \\1= possible b0, \\2=name" ) ; static (defvar gellmu-opc-re "\\(\\[\\|{\\)") ; static "\\3": "[" or "{" (defvar gellmu-tot-re (concat gellmu-com-re gellmu-opc-re) "Gellmu: RE, \\ + \\1 + \\2 + \\3; \\1=\"b0\" ?, \\2=name, \\3={ or [" ) (defvar gellmu-curr-ops "") (defvar gellmu-curr-opc 0) (defvar gellmu-aolist nil "Gellmu: List of args/options for \\command{...}") (defvar gellmu-stmp "") (defvar gellmu-ctmp 0) (defvar gellmu-ltmp 0) (defvar gellmu-ktmp 0) (defvar gellmu-tmp-tmp 0) (defvar gellmu-tmem nil) (defvar gellmu-curr-elt "" "Name of command in a \\command{...} situation." ) (defvar gellmu-complex-tag nil "True if \\command{...} has any option or more than one arg/opt Note that the usage \foo{untagged content} does NOT give rise to an arg in this sense since there are no subelements of at the outset." ) (defvar gellmu-closetag-flag nil "True if a close-tag has been written for \\command{...}" ) (defvar gellmu-soleoptonly-flag nil "True if a command was entered with the usage \"\\foo[some opt]\" without other args or opts; in this case there will be no automatic end tag" ) (defvar gellmu-autoclose-flag nil) ;; Turn off some things if this is going to be regular sgml. (if gellmu-straight-sgml (progn (setq gellmu-regular-sgml t) (setq gellmu-no-parb t) ) ) (if gellmu-regular-sgml (progn (setq gellmu-no-latex t) (setq gellmu-nbs-repn "~") (setq gellmu-no-auto-sol t) ) () ) ;; Is this an empty buffer? (if (= (point-min) (point-max)) (if noninteractive (error "Gellmu input buffer (from file \"%s\") is empty" gellmu-full-filename ) (error "Gellmu interactive input buffer is empty" ) ) ; end of if non-interactive -- empty buffer () ; non-empty buffer ) (if (string-equal gellmu-debug-id "early") (gellmu-debug-exit gellmu-write-buff) () ) ;; Is this a GELLMU document? ;; Beginning of MAIN SEXP -- names in here should be hidden, ; ; debug-id "setup" (let ( (balbr ?\{) (balbk ?\[) (balpr ?\() (sufoffset nil)) ;; Set up new buffer for translated doc (setq gellmu-buff-name (buffer-name)) (fset 'gellmu-output-mode-command (intern gellmu-output-mode-command)) (setq sufoffset (string-match gellmu-input-suffix-regexp gellmu-buff-name) ) (if sufoffset (setq gellmu-write-buff (concat (substring gellmu-buff-name 0 (match-beginning 0)) gellmu-output-suffix)) ;(setq gellmu-write-buff (concat gellmu-buff-name "00")) (setq gellmu-write-buff (concat gellmu-buff-name gellmu-output-suffix)) ) ;(setq glm-err-str "Buffer name: %s\nWrite buffer: %s") ;(gellmu-message (format glm-err-str gellmu-buff-name gellmu-write-buff)) (generate-new-buffer gellmu-write-buff) (copy-to-buffer gellmu-write-buff (point-min) (point-max)) ; Should these next two lines be changed for batch use? (switch-to-buffer-other-window gellmu-write-buff) ; (gellmu-output-mode-command) ; now or ever? (setq case-fold-search nil) (if (string-equal gellmu-debug-id "setup") (gellmu-debug-exit gellmu-write-buff) () ) ;; Wash the GELLMU for whitespace and comments ; ; debug-id "prewash" ;; Make sure that the write-buffer ends with a newline (goto-char (point-max)) (if (char-equal (preceding-char) ?\n) () (insert ?\n)) ;; Replace each TAB with two spaces. ; Then there will be no TABs. (goto-char (point-min)) (while (search-forward "\t" nil t) (replace-match " " t t) ) ;; Make each line that looks blank a truly blank line. (goto-char (point-min)) (while (re-search-forward "\n[ ]+\n" nil t) ; (tabs are already gone) (replace-match "\n\n" t t) ) (setq gellmu-macro-start (point-min)) (if (string-equal gellmu-debug-id "prewash") (gellmu-debug-exit gellmu-write-buff) () ) ;; Clean verbatim zones ; ; debug-id "cleanverbatim" (if gellmu-verbatim-clean (let (zvbb zvbe tbody body) (goto-char gellmu-macro-start) (while (re-search-forward "\n *\\\\begin{verbatim} *\n" nil t) ;(setq zvbb (match-end 0)) ; just after "\begin{verbatim}\n" ;(goto-char zvbb) (replace-match "\n\\begin{verblist}\n" t t) (backward-char) (setq zvbb (point)) (if (not (re-search-forward "\n *\\\\end{verbatim} *\n" nil t) ) (progn (goto-char zvbb) (what-line) (error (format "No forward instance of \"\\end{verbatim}\" on a line by itself to match \"\\begin{verbatim}\"") ) ) ) ; end of test for \end{verbatim} ;(setq zvbe (match-beginning 0)) ; before "\n\end{verbatim}" ;(setq zvbe (1- (match-beginning 0))) (setq zvbe (match-beginning 0)) (replace-match "\n\\end{verblist}\n" t t) (setq tbody (buffer-substring zvbb zvbe)) (goto-char zvbb) (while (< (point) zvbe) (delete-char 1) (setq zvbe (1- zvbe)) ) (setq body (gellmu-clean-verbatim tbody)) (insert body) ) ; end of the while block ) ) (if (string-equal gellmu-debug-id "cleanverbatim") (gellmu-debug-exit gellmu-write-buff) () ) ;; Manmac-like vertical bars for quostr -- ; ; only if gellmu-manmac-bar-name is not "" ; ; debug-id "manmac" (if (and (not gellmu-regular-sgml) (not (string-equal gellmu-manmac-bar-name "")) ) (let ( (gThree "\\([A-Za-z]+\\)") (gFour "\\([^|\n]+\\)") (gOne "")(gTwo "") (gbre "") name prec tbody body (quostr "") (quosatt "") front (tail "}") value ) (goto-char gellmu-macro-start) (setq gTwo ( concat "\\(\\\\" gThree "\\)" ) ) (setq gOne ( concat "\\(" gTwo "\\)?" )) (setq gbre (concat gOne "|" gFour "|")) ; ; i.e. gbre is "\(\(\\\([A-Za-z]+\)\)\)?|\([^|]+\)|" ; (setq quostr (concat "\\" gellmu-manmac-bar-name)) (if (not (string-equal gellmu-manmac-bar-attribute "")) (setq quosatt (concat "[: " gellmu-manmac-bar-attribute "=\"")) ) (while (re-search-forward gbre nil t) (if (match-string 3) (progn (setq name (match-string 3)) (if (not (string-equal quosatt "")) (setq front (concat quostr quosatt name "\"]{")) (setq front (concat quostr "{")) ) ) (progn (setq front (concat quostr "{")) ) ) (setq body (match-string 4)) (if gellmu-manmac-literal (progn ; Need to be careful not to overwrite the match with ; the call to gellmu-render-literal (replace-match "" t t) (setq tbody body) (setq body (gellmu-render-literal tbody)) (setq value (concat front body tail)) (insert value) ) (replace-match (concat front body tail) t t) ) ) ; end of while re-search-forward gbre ) ) (if (string-equal gellmu-debug-id "manmac") (gellmu-debug-exit gellmu-write-buff) () ) ; ; debug-id "wash" ;; Get Rid of all TeX-Like Comments (goto-char (point-min)) ; line = all comment (while (re-search-forward "^%.*$" nil t) (if gellmu-regular-sgml (replace-match " " t t) (replace-match "\\nul;" t t) ;; whole-line comment -> "\nul" ) ) (goto-char (point-min)) ; line = white space + comment (while (re-search-forward "^[ \t][ \t]*%.*$" nil t) (if gellmu-regular-sgml (replace-match "\n" t t) (replace-match "\\cw0;" t t) ;; whole-line of white + comment -> "\cw0" ) ) (goto-char (point-min)) ; line = markup + white space +comment (while (re-search-forward "\\([ \t]\\)%.*$" nil t) (if gellmu-regular-sgml (replace-match " " t t) (replace-match "\\1\\\\cs0;" t) ;; EOL comment after space -> "\cs0" ) ) (goto-char (point-min)) ; line = markup + comment (no intervening space) (while (re-search-forward "\\([^\\\n]\\)%.*$" nil t) (if gellmu-regular-sgml (replace-match "\\1" t) (replace-match "\\1\\\\cm0;" t) ;; EOL comment -> "\cm0" ) ) (if (string-equal gellmu-debug-id "wash") (gellmu-debug-exit gellmu-write-buff) () ) ;; Cleanse the GELLMU. ; ; The "cleanse" segment originally followed "wash". It was moved ; ; after the "expansions" exit in order to make expansions output look ; ; good. But that has the problem that gellmu-balance-pair-forward, ; ; which, for speed, does not check whether either '{' or '}' is ; ; preceded by '\', is fooled by '\{' or '\}' inside macro, mathsym, ; ; and newcommand arguments. So the code is back here. The ; ; expansions output is tidied by some restorations. ;; Cleanse Escaped Chars and Shortrefs. ;; The Character "\": the basic GELLMU command introducer ; First we need to replace each RE "\([^\]\)\\\\\([ \n]\)" ; with the rep-RE "\1\\brk;\2" ; Second we need to go through replacing each STRING "\\" by "\bsl;" ; Then replace each STRING "\{" by "\lbr;" and "\}" by "\rbr;" ; It's too soon to SGML-ize these since we have not yet made the ; output safe for SGML. ; ; debug-id "cleanse" (if gellmu-regular-sgml (progn (goto-char (point-min)) ;; replace all "\\" with "\bsl;" (while (search-forward "\\\\" nil t) (replace-match "\\bsl000;" t t) ; 2000-09-09 -- added semi-colon ) ) (progn (goto-char (point-min)) ;; replace legit. "\\" with "\brk0" ; (while (re-search-forward "\\([^\\]\\)\\\\\\\\\\([ \n]\\)" nil t) ; (replace-match "\\1\\\\brk0 \\2" t)) (while (re-search-forward "\\\\\\\\\\([ \n]\\)" nil t) (replace-match "\\\\brk0 \\1" t)) (goto-char (point-min)) ;; replace dubious "\\" with "\bsl;" (while (search-forward "\\\\" nil t) (what-line) (gellmu-message (format "Gellmu: dubious string \"\\\\\"") ) (replace-match "\\bsl;" t t) ) ) ) ;; The Character "{": the GELLMU zone opener (goto-char (point-min)) ;; replace "\{" with "\lbr;" (while (search-forward "\\{" nil t) (if gellmu-regular-sgml (replace-match "\\lbr000;" t t) ; 2000-09-08 -- added semi-colon (replace-match "\\lbr;" t t) ) ) ;; and its twin "}": the GELLMU zone closer (goto-char (point-min)) ;; replace "\}" with "\rbr;" (while (search-forward "\\}" nil t) (if gellmu-regular-sgml (replace-match "\\rbr000;" t t) ; 2000-09-08 -- added semi-colon (replace-match "\\rbr;" t t) ) ) ;; '#' escaped with '\#' (goto-char (point-min)) ;; replace "\#" with "\hsh;" (while (search-forward "\\#" nil t) (if gellmu-regular-sgml (replace-match "\\hsh000;" t t) (replace-match "\\hsh;" t t) ) ) (if (string-equal gellmu-debug-id "cleanse") (gellmu-debug-exit gellmu-write-buff) () ) ; ; WARNING: Code after this point makes extensive use of ; gellmu-balance-pair-forward which assumes that all instances ; of the balancing characters '{' and '}' are "live". ; That is why the cleansing code is above. ;; code for basic macros: cf. gellmu-macro-name ; ; As it is this code works anywhere in the document provided only ; ; that a macro is not invoked prior to its definition ; ; Minor issue: could this be made to come before comment handling? ; ; Presently comments cannot be place in the middle of a macro defn. ; ; debug-id "macro" ;<--- (goto-char gellmu-macro-start) (let ( (ome "\\(") (cme "\\)") (nobr "[^{}]*") (lito "[A-Za-z][0-9A-Za-z]*") (mname "") (mvalue "") (mbase 0) (mtarg 0) (mzb 0) (mze 0) (mline "") (mloc 0) (rc 0) (rstr "") (tstr "") ) (setq mbase (point)) ;; Loop forward looking for macro defns (while (search-forward (concat "\\" gellmu-macro-name "{") nil t) ;; Get the macro name (setq mzb (point)) ; just after "{", first in mname (setq mbase (match-beginning 0)) (backward-char) (gellmu-balance-pair-forward ?{ 2) ; just after "}" (backward-char) (setq mze (point)) ; last in mname -- location saved as mze (setq mname (buffer-substring mzb mze)) ;; Get the macro value ; point not moved from mze unless this code has changed (forward-char) ; just after "}": but are we just before "{" ; ; Maybe allow a single newline here? ; ; E.g., (if (= (char-after) ?\n)(forward-char 1)) (if (not (= (char-after) ?{)) (progn (what-line) (error "Ill-formed second argument to %s instance \"%s\"" gellmu-macro-name mname ) ) () ) (setq mzb (1+ (point))) ; first in mvalue (gellmu-balance-pair-forward ?{ 2) ; just after next "}" (backward-char) (setq mze (point)) ; last in mvalue (setq mvalue (buffer-substring mzb mze)) ;; Clean up the macro definition site (goto-char mbase) (setq mtarg (1+ mze)) (while (< (point) mtarg) (delete-char 1) (setq mtarg (1- mtarg)) ) ; At this point we may be at the end of a blank line ; This is the case, for example, if the whole macro command ; was the sole content of a line. We do not want a blank line. (setq mloc (point)) (beginning-of-line) (setq mzb (point)) (end-of-line) (setq mze (point)) (goto-char mloc) (if (not gellmu-regular-sgml) (progn (if (= mzb mze) (insert "\\nul;") ; totally blank line ; non-blank line -- we may assume mzb < mze (setq mline (buffer-substring mzb mze)) (if (string-match "\\w" mline) ; word constituent (if (= (char-before) ? ) (insert "\\cs0;") ; space then non-trivial content (insert "\\cm0;") ; non-trivial content ) ; line has only non-word content, whitespace with luck (insert "\\cw0;") ) ) ) ) ;; Perform the macro substitutions (while (re-search-forward (concat ;;; The first argument to concat used to be "\\\\" ;(regexp-quote mname) ome ";" cme "?" ome "[^0-9A-Za-z]" cme) (regexp-quote mname) ome ";" cme "?" ) nil t) ; cannot use replace-match in non-literal mode, due to possible ; upset about '\' in mvalue ;(setq rstr (concat mvalue (match-string 2))) ;(replace-match rstr t t) (replace-match mvalue t t) ) (goto-char mbase) ) ; end of while-search-forward gellmu-macro-name ) ; end of code for basic macros (if (string-equal gellmu-debug-id "macro") (gellmu-debug-exit gellmu-write-buff) () ) ;; code for math symbol declarations ; ; Usage: \mathsym{name}{gellmu-expansion}[optional] ; ; About the optional argument: ; ; 1. It is optional. ; ; 2. If present, it must be a string without markup. ; ; 3. It is otherwise unstructured from the point of view of ; ; the syntactic translator. ; ; 4. Its purpose is to provide semantic hints, such as a type ; ; for the symbol under *your* type scheme or a hint for ; ; rendering in something like MathML or both or ... ; ; debug-id "mathsym" (goto-char gellmu-macro-start) (let ( (ome "\\(") (cme "\\)") (nobr "[^{}]*") (lito "[A-Za-z][0-9A-Za-z]*") (syname "") (syvalue "") (sybase 0) (sytarg 0) (syzb 0) (syze 0) (syline "") (syloc 0) (rc 0) (rstr "") (tstr "") (sysole "") (symeta "") ) (setq sybase (point)) ;; Loop forward looking for mathsym defns (while (search-forward (concat "\\" gellmu-mathsym-name "{") nil t) ;; Get the mathsym first argument ; ; It's the name if this is a first pass. Otherwise this is the ; ; only argument and results from a third argument in first pass. (setq syzb (point)) ; just after "{", first in syname (setq sybase (match-beginning 0)) (backward-char) (gellmu-balance-pair-forward ?{ 2) ; landing just after "}" ; Is there another argument? (if (= (char-after) ?{) (progn ; not a sole mathsym arg. ; (backward-char) ; now just before "}" (setq syze (point)) ; last in syname -- location saved as syze (setq syname (buffer-substring syzb syze)) ; strip any leading '\' from syname (setq tstr syname) (setq rc (string-match "\\\\" syname)) (if rc (if (< 0 rc) (progn (what-line) (error "Illegal backslash in mathsym name \"%s\"" syname) ) ; backslash at offset 0 in syname (setq tstr (substring syname 1)) (setq syname tstr) (goto-char syzb) (delete-char 1) (setq syze (1- syze)) ) ; end of if 0 < rc ) ; end of if rc ; Check for non-word constituent in syname ; ; Ummm... this regexp is mode-dependent; watch your mode (setq rc (string-match "\\W" syname)) (if rc (progn (what-line) (error "Non-word constituent in mathsym name \"%s\"" syname ) ) ) (goto-char syze) ; just before "}" -- delete it (delete-char 1) ; ) ; end of first mathsym arg. handling when there's another arg. (progn ; sole mathsym arg. ; now just after "}" for the first and only argument (backward-char) (setq syze (point)) ; last in syname -- location saved as syze (setq sysole (buffer-substring syzb syze)) (forward-char) ; again just after 1st arg's "}", which stays (setq sybase (point)) ; otherwise we loop through here ) ; end of handling for mathsym with sole arg. ) ; ; Again: are we just before "{" (a 2nd arg for "value")? ; ; Maybe allow a single newline here? ; ; E.g., (if (= (char-after) ?\n)(forward-char 1)) (if (= (char-after) ?{) (progn ; new block for more than one argument begins here, ca. 90 lines ; just before "{": value argument processing begins here (setq syzb (1+ (point))) ; first in syvalue (gellmu-balance-pair-forward ?{ 2) ; just after next "}" (backward-char) ; just before "}" (setq syze (point)) ; last in syvalue (setq syvalue (buffer-substring syzb syze)) ; clean comment residue from syvalue according to LaTeX rules (if gellmu-regular-sgml ; but presumably not when mathsym is used (while ; no visible comment residue (string-match "\n *" syvalue) (setq syvalue (replace-match "" t t syvalue)) ; Why not " " ?? ) (while (string-match "\\\\\\(nul\\|cm0\\|cs0\\|cw0\\);\n *" syvalue) (setq syvalue (replace-match "" t t syvalue)) ) ) ; clean up the syvalue source area (goto-char syzb) (delete-backward-char 1) ; remove the "{" (setq syzb (1- syzb)) (setq syze (1- syze)) (setq sytarg syze) (while (< (point) sytarg) (if (= (char-after) ?\n) ; (if gellmu-regular-sgml ; well, presumably *not* regular-sgml ; (forward-char) ; when mathsym is used ; ; not regular-sgml ; (insert "\\nul;") ; (setq sytarg (+ 5 sytarg)) ; the length of "\nul;" ; (forward-char) ; ) ; case: char-after is ?\n ; So long as \mathsym is only in the preamble don't need \nul's (forward-char) ; leave \n in place for line number alignment ; case: char-after is not ?\n (delete-char 1) (setq sytarg (1- sytarg)) ) ) ; original syvalue string and its "{" now gone -- facing "}" (if (not (= (char-after) ?\})) (progn (what-line) (error "Gellmu-trans: logical error in %s code; Looking at \"%s\"" gellmu-mathsym-name (buffer-substring (- (point) 5) (+ (point) 5)) ) ) (forward-char) ; just after the "}" ) ;; Look for optional final argument with meta info (if (= (char-after) ?\[) (progn ; have optional argument ; remove the preceding "}" (delete-backward-char 1) (setq syzb (point)) ; just before "[" (gellmu-balance-pair-forward ?\[ 2) ; now after "]" ; replace the "]" with "}" (delete-backward-char 1) (insert "}") (backward-char) (setq syze (point)) ; point before "}" (goto-char syzb) (delete-char 1) ; remove the "[" (insert " ") ; separate optional arg from name arg (while (re-search-forward "\\\\\\(nul\\|cm0\\|cs0\\|cw0\\);" syze t) (replace-match "" t t) (setq syze (- syze 5)) ) (goto-char syze) (forward-char) ) ) ; end of optional mathsym argument handling (setq sybase (point)) ;; Perform the mathsym substitutions (while (re-search-forward (concat "\\\\" (regexp-quote syname) ome ";" cme "?" ome "[^0-9A-Za-z]" cme) nil t) ; cannot use replace-match in non-literal mode, due to possible ; upset about '\' in syvalue (setq rstr (concat "\\" gellmu-mathsym-wrapper "[:" gellmu-symkey-name "=\"" syname "\"]" "{" syvalue "}" (match-string 2) ) ) (replace-match rstr t t) ) ; end of while for mathsym substitutions ) ; end of new block for mathsym with more than one argument ) ; end of enveloping if for previous block (goto-char sybase) ) ; end of while-search-forward gellmu-mathsym-name ) ; end of code for mathsym (if (string-equal gellmu-debug-id "mathsym") (gellmu-debug-exit gellmu-write-buff) () ) ;; Newcommand processing: macros with arguments ; ; Usage like LaTeX2E ; ; \newcommand{NAME}[NARGS][DEFAULT-FIRST]{DEFINITION} ; ; NARGS is not required but is enforced if present ; ; NARGS without limit ... ; ; ... since the author has a background in theta functions ; ; NARGS is required if DEFAULT-FIRST is present ; ; If (at invocation) NREFS > NARGS, an error occurs. ; ; If (at invocation) NREFS < NARGS, a warning is given. ; ; ; ; debug-id "newcom" (goto-char gellmu-macro-start) (let ; externals inside this "let": ; ; gellmu-newcommand-name ; ; gellmu-no-diagnostic-output ; ; gellmu-regular-sgml ( (ome "\\(") (cme "\\)") (nobr "[^{}]*") (lito "\\w*") (ncname "") (ncvalue "") (argc 0) (argv ()) (ncbase 0) (nctarg 0) (nczb 0) (ncze 0) (ncline "") (ncloc 0) (rc 0) (tstr "") (ncargf nil) (ncargs 0) (max 9) (ncfirst "") (ncopts 0) (ncshift 0) (ncib 0) (ncie 0) (ncil 0) (ncit 0) (ncrepl "") (invre "") (ncerl 0) (ncerca 0) (ncercb 0) (ncregexp "")) ;; Loop forward looking for newcommand defns (setq ncbase (point)) (while (search-forward (concat "\\" gellmu-newcommand-name "{") nil t) ;; Get the newcommand name (setq nczb (point)) ; just after "{", first in ncname (setq ncbase (match-beginning 0)) (backward-char) (gellmu-balance-pair-forward ?{ 2) ; point just after "}" (backward-char) ; point just before "}" (setq ncze (point)) ; last in ncname -- location saved as ncze (if (not (< nczb ncze)) (progn (what-line) (error "Instance of %s must provide non-empty name" gellmu-newcommand-name ) ) ) (setq ncname (buffer-substring nczb ncze)) (if (not gellmu-no-diagnostic-output) (send-string-to-terminal (format "Found %s \"%s\"\n" gellmu-newcommand-name ncname) )) ; strip any leading '\' from ncname (setq tstr ncname) (setq rc (string-match "\\\\" ncname)) (if rc (if (< 0 rc) (progn (what-line) (error "Illegal backslash in %s name \"%s\"" gellmu-newcommand-name ncname) ) ; backslash at offset 0 in ncname (setq tstr (substring ncname 1)) (setq ncname tstr) ) ; end of if 0 < rc ) ; end of if rc ; ; ; No checking at all on ncname; Be Careful ; Check for non-word constituent in ncname ;(setq rc (string-match "\\W" ncname)) ;(if rc ; (error "Non-word constituent in %s name \"%s\" at %s" ; gellmu-newcommand-name ncname (what-line) ; ) ;) ;; Look for newcommand options ; point not moved from ncze unless this code has changed (setq ncopts 0) (setq ncargf nil) (setq ncargs 0) (setq ncfirst "") (setq argc 0) ; 20080525 (forward-char) ; just after name then "}" -- "[" or "{" must follow ; ; Allow a newline here in case there are no options (if (not (or (= (char-after) ?{) (= (char-after) ?\[) (= (char-after) ?\n))) (progn (what-line) (error "Bad argument syntax for %s instance \"%s\"" gellmu-newcommand-name ncname ) ) ) ; Either "[" or "{" or "\n" at point; examine any options (while (= (char-after) ?\[) (setq ncopts (1+ ncopts)) (if (= ncopts 1) (progn ; case: ncopts is 1 ; grab ncargs value, test if integral (setq ncargf t) (setq nczb (1+ (point))) (gellmu-balance-pair-forward ?\[ 2) (setq ncze (1- (point))) (cond ; for sanity of nczb ncze ((= nczb ncze) (progn (what-line) (error "%s instance \"%s\": empty value for no. of args" gellmu-newcommand-name ncname) ) ) ((< nczb (point-min)) (error "Coding error for newcommand: nczb < point-min") ) ((< (point-max) ncze) (error "Coding error for newcommand: ncze > point-max") ) ((< ncze nczb) (progn (what-line) (error "%s instance \"%s\": coding error %d < %d !! ??" gellmu-newcommand-name ncname ncze nczb) ) ) ) (setq ncargs (string-to-number (buffer-substring nczb ncze))) (if (< ncargs 0) (error "NARGS opt %d for %s instance \"%s\" < 0 !?" ncargs gellmu-newcommand-name ncname) ; ; But maybe allow a single newline here after the first option ; ; E.g., (if (= (char-after) ?\n)(forward-char 1)) ) ) ; end of ncopts is 1 (if (= ncopts 2) (progn ; grab first argument default in variable ncfirst (setq nczb (1+ (point))) (gellmu-balance-pair-forward ?\[ 2) (setq ncze (1- (point))) (setq ncfirst (buffer-substring nczb ncze)) ) ; end of ncopts is 2 ; not 1 or 2 options (what-line) (error "Too many options (%d) for %s instance \"%s\"" ncopts gellmu-newcommand-name ncname ) ) ; end of if-ncopts = 2 ) ; end of if-ncopts = 1 ) ; end of while char-after = '[' ;; Get the newcommand definition ; Allow a single newline here before the value string (if (= (char-after) ?\n) (forward-char 1)) (if (not (= (char-after) ?{)) (progn (setq ncerca (char-after)) (setq ncercb (char-before)) (setq ncerl (point)) (beginning-of-line) (what-line) (error "Cannot find value definition for %s \"%s\" between hex %x and hex %x at line offset %d" gellmu-newcommand-name ncname ncercb ncerca (- ncerl (point)) ) ) ) (setq nczb (1+ (point))) ; first in ncvalue (gellmu-balance-pair-forward ?{ 2) ; just after next "}" (setq ncze (1- (point))) ; last in ncvalue (setq ncvalue (buffer-substring nczb ncze)) ; Clean out all comment residue in ncvalue with LaTeX rules ; under which initial blanks on the next line are swallowed (if gellmu-regular-sgml (while ; no visible comment residue (string-match "\n *" ncvalue) (setq ncvalue (replace-match "" t t ncvalue)) ) (while (string-match "\\\\\\(nul\\|cm0\\|cs0\\|cw0\\);\n *" ncvalue) (setq ncvalue (replace-match "" t t ncvalue)) ) ) ; Safety: Don't allow ncname in ncvalue (setq ncregexp (concat "\\\\" (regexp-quote ncname) "\(\\W\\|\\$\)" ) ) (if (and ncargf (string-match ncregexp ncvalue 1 ) ) (progn (what-line) (error "Newcommand \"%s\": bad reference to self in definition\n -- offset %d in value string \"%s\"\n -- checked with regexp \"%s\"\n" ncname (match-beginning 0) ncvalue ncregexp ) ) ) ;; Clean up the newcommand definition site ; ; This preserves line number alignment at the newcommand site. ; For regular SGML, where the document type is beyond control, ; we leave blank lines instead of comment residue. For full GELLMU ; blank lines in the preamble will not cause parb problems. ; (But what if we are not in a preamble? Better turn off parb then.) ; Leave comment residue. ; NOTE: Newlines are permitted in value strings. They spoil ; line number alignment at the invocation site. So they are not ; a good idea if author debugging is important. (goto-char ncbase) (setq nctarg (1+ ncze)) (while (< (point) nctarg) (if (= (char-after) ?\n) (if gellmu-regular-sgml (forward-char) ; not regular-sgml (insert "\\nul;") (setq nctarg (+ 5 nctarg)) ; the length of "\nul;" (forward-char) ) ; case: char-after is ?\n ; case: char-after is not ?\n (delete-char 1) (setq nctarg (1- nctarg)) ) ) ; For other than regular-sgml: ; ; At this point we may be at the end of a blank line ; ; This is the case, for example, if the whole newcommand ; ; was the sole content of a line. We do not want a blank line. (if (not gellmu-regular-sgml) (progn ; case: not regular-sgml (setq ncloc (point)) (beginning-of-line) (setq nczb (point)) (end-of-line) (setq ncze (point)) (goto-char ncloc) (if (= nczb ncze) (insert "\\nul;") ; totally blank line ; non-blank line -- we may assume nczb < ncze (setq ncline (buffer-substring nczb ncze)) (if (string-match "\\w" ncline) ; word constituent (if (= (char-before) ? ) (insert "\\cs0;") ; space then non-trivial content (insert "\\cm0;") ; non-trivial content ) ; line has only non-word content, whitespace with luck (insert "\\cw0;") ) ) ; end of if nczb = ncze and end of case: not gellmu-regular-sgml ) ; end of progn for case: not-regular-sgml true ) ; end of if not regular-sgml ;; Perform the newcommand invocation substitutions (setq invre (concat "\\\\" (regexp-quote ncname) ome "\\W\\|\\$" cme) ) ;; Find next invocation instance of this newcommand (while ; re-search-forward for invocation (re-search-forward invre nil t) ; ; Enter args, if any, via cons in argv, which will be LIFO ; ; Note: We cannot use add-to-list because two args could be ; ; identical strings. So we need to use the construction ; ; (setq argv (cons nextarg argv)) ; ; Then (setq argc (length argv)) ; ; Compare argc with ncargs if the latter is non nil (setq ncil (match-beginning 0)) ; origin of invocation markup (setq ncit 0) ; since we haven't seen the end yet (if (not gellmu-no-diagnostic-output) (send-string-to-terminal (format "--> %s invocation \"%s\" \"%s\" [%d] (\"%s\") at %d Context: %s\n" gellmu-newcommand-name ncname ncvalue ncargs ncfirst ncil (buffer-substring (- ncil 10) (min (+ ncil 35) (point-max))) ) )) (setq argv ()) (setq ncrepl ncvalue) ; copy of ncvalue for this invocation ; Point is just after the match, i.e., one too far ; For example, \fooname;{...} means that {...} is a logical group. (backward-char 1) (if (not (= (char-after) ?\;)) ; Allow the first invocation argument to have option syntax (progn (if (= (char-after) ?\[) (progn (setq ncib (1+ (point))) (gellmu-balance-pair-forward ?\[ 2) (setq ncie (1- (point))) (setq argv (cons (buffer-substring ncib ncie) argv)) ) ) (while (= (char-after) ?{) (setq ncib (1+ (point))) (gellmu-balance-pair-forward ?{ 2) (setq ncie (1- (point))) (setq argv (cons (buffer-substring ncib ncie) argv)) ) ) ; In the case where "foo" is a newcommand name the invocation ; \foo;abc is used to prevent the misinterpretation "\fooabc". ; The construction of the value string must be aware of possible ; abutment against a word. (delete-char 1) ; delete the ";" used to terminate the invocation ) (setq ncit (point)) ; end of invocation markup ; We now have grabbed all of the invocation's arguments ; and point follows the last "}", if any (if (not gellmu-no-diagnostic-output) (send-string-to-terminal (format " Arguments: No. of invocation args: %d Location (range): %d -- %d Value string: %s Value of 1st, last arg: >%s< >%s<\n" (length argv) ncil ncit ncrepl (if (< 0 (length argv)) (elt argv (1- (length argv))) "") (if (< 1 (length argv)) (elt argv 0) "") ) )) ; ; Remove the invocation markup (if (< ncit (+ ncil 2)) ; is this deletion safe? (progn (what-line) (error "Error in translator code logic for newcommand invocation cleanup; invocation of newcommand %s with %d args\n" ncname (length argv) ) ) ) (goto-char ncil) (while (< (point) ncit) (delete-char 1) (setq ncit (1- ncit)) ) ; point should still be at ncil ; ; Is the invocation's argument list sane? (setq argc (length argv)) (setq ncshift 0) (if ncargf ; ncargs was set (cond ; for arg sanity ((< ncargs argc) ; clause 1 (progn (what-line) (error "Too many args %d; invocation of newcommand %s, NARGS is %d" argc ncname ncargs ) ) ) ; end of clause 1 ((< (1+ argc) ncargs) ; clause 2 (progn (what-line) (error "Too few args %d; invocation of newcommand %s, NARGS is %d" argc ncname ncargs ) ) ) ; end of clause 2 ((= (1+ argc) ncargs) ; clause 3 ; Need to use ncfirst if the author provided it, else error (if (not (= ncopts 2)) (progn (what-line) (error "Too few args %d; newcommand invocation %s, NARGS is %d, NCOPTS is %d" argc ncname ncargs ncopts ) ) ) (if (not gellmu-no-diagnostic-output) (send-string-to-terminal (format " Using default first arg.\n"))) (while (string-match "#1" ncrepl) (setq ncrepl (replace-match ncfirst t t ncrepl)) ) ; ncshift = 1 means that argv[1] --> #2, argv[2] --> #3, ... (setq ncshift 1) ; ) ; end of clause 3 ) ; end of cond for arg sanity (progn ; ncargf not set -- unacceptable if argc > 0 (if (< 0 argc) (progn (what-line) (if (= 1 argc) (error "Unexpected argument; newcommand invocation %s" ncname ) (error "%d unexpected arguments; newcommand invocation %s" argc ncname ) ) ) ) ) ) ; end of if ncargf (true) (if (not gellmu-no-diagnostic-output) (send-string-to-terminal (format " Arguments appear to be OK.\n") )) ; ; Make arg substitutions in ncrepl for this invocation ; cannot use replace-match in non-literal mode, due to possible ; upset about '\' in ncrepl, i.e., use (replace-match whatever t t) (let ((jarg 0) (jslot 0) (jre "")) ; ncrepl subs (while (< 0 (length argv)) (setq jarg (length argv)) (setq jslot (+ jarg ncshift)) (setq jre (concat "#" (number-to-string jslot))) (while (string-match jre ncrepl) (setq ncrepl (replace-match (car argv) t t ncrepl)) ) (setq argv (cdr argv)) ) ) ; end of let for ncrepl subs ; ; Insert ncrepl at ncil (where the invocation had been) (goto-char ncil) (insert ncrepl) ; get in position for next round in substitution loop ; If we continue from here we'll miss recursive references. ; For semi-safety don't go back unless there's an NCARGS spec ; Moving forward just a single char can lead to an infinite ; loop. (if ncargf (progn ; live dangerously (goto-char ncil) (forward-char) ) () ; stay safe when the NCARGS option is not present ) ) ; end of while re-search-forward for invocation (goto-char ncbase) ; to process the next newcommand defn ) ; end of while-search-forward gellmu-newcommand-name ) ; end of code for newcommand (if (string-equal gellmu-debug-id "newcom") (gellmu-debug-exit gellmu-write-buff) () ) ;<--- ;; code for late macro expansion: cf. gellmu-late-macro-name ; ; Removed the requirement for invocations to begin with "\" ; ; If you don't want to live dangerously, use "\newcommand" ; ; or at least begin names with "\". ; ; The name for a Macro is now *exactly* what is in the ; ; defining braces. USE "\Macro" WITH EXTREME CAUTION. ; ; debug-id "latemacro" ;<--- (goto-char gellmu-macro-start) (let ( (ome "\\(") (cme "\\)") (nobr "[^{}]*") (lito "[A-Za-z][0-9A-Za-z]*") (mname "") (mvalue "") (mbase 0) (mtarg 0) (mzb 0) (mze 0) (mline "") (mloc 0) (rc 0) (rstr "") (tstr "") ) (setq mbase (point)) ;; Loop forward looking for macro defns (while (search-forward (concat "\\" gellmu-late-macro-name "{") nil t) ;; Get the macro name (setq mzb (point)) ; just after "{", first in mname (setq mbase (match-beginning 0)) (backward-char) (gellmu-balance-pair-forward ?{ 2) ; just after "}" (backward-char) (setq mze (point)) ; last in mname -- location saved as mze (setq mname (buffer-substring mzb mze)) ;; Get the macro value ; point not moved from mze unless this code has changed (forward-char) ; just after "}": but are we just before "{" ; ; Maybe allow a single newline here? ; ; E.g., (if (= (char-after) ?\n)(forward-char 1)) (if (not (= (char-after) ?{)) (progn (what-line) (error "Ill-formed second argument to %s instance \"%s\"" gellmu-late-macro-name mname ) ) () ) (setq mzb (1+ (point))) ; first in mvalue (gellmu-balance-pair-forward ?{ 2) ; just after next "}" (backward-char) (setq mze (point)) ; last in mvalue (setq mvalue (buffer-substring mzb mze)) ;; Clean up the macro definition site (goto-char mbase) (setq mtarg (1+ mze)) (while (< (point) mtarg) (delete-char 1) (setq mtarg (1- mtarg)) ) ; At this point we may be at the end of a blank line ; This is the case, for example, if the whole macro command ; was the sole content of a line. We do not want a blank line. (setq mloc (point)) (beginning-of-line) (setq mzb (point)) (end-of-line) (setq mze (point)) (goto-char mloc) (if (not gellmu-regular-sgml) (progn (if (= mzb mze) (insert "\\nul;") ; totally blank line ; non-blank line -- we may assume mzb < mze (setq mline (buffer-substring mzb mze)) (if (string-match "\\w" mline) ; word constituent (if (= (char-before) ? ) (insert "\\cs0;") ; space then non-trivial content (insert "\\cm0;") ; non-trivial content ) ; line has only non-word content, whitespace with luck (insert "\\cw0;") ) ) ) ) ;; Perform the macro substitutions (while (re-search-forward (concat ;;; The first argument to concat used to be "\\\\" ;(regexp-quote mname) ome ";" cme "?" ome "[^0-9A-Za-z]" cme) (regexp-quote mname) ome ";" cme "?" ) nil t) ; cannot use replace-match in non-literal mode, due to possible ; upset about '\' in mvalue ;(setq rstr (concat mvalue (match-string 2))) ;(replace-match rstr t t) (replace-match mvalue t t) ) (goto-char mbase) ) ; end of while-search-forward gellmu-late-macro-name ) ; end of code for basic macros (if (string-equal gellmu-debug-id "latemacro") (gellmu-debug-exit gellmu-write-buff) () ) ; ; debug-id "expansions" (if gellmu-expansions-only (progn (if gellmu-regular-sgml (progn (goto-char (point-min)) (while (search-forward "\\bsl000;" nil t) (replace-match "\\\\" t t)) (goto-char (point-min)) (while (search-forward "\\lbr000;" nil t) (replace-match "\\{" t t)) (goto-char (point-min)) (while (search-forward "\\rbr000;" nil t) (replace-match "\\}" t t)) (goto-char (point-min)) (while (search-forward "\\hsh000;" nil t) (replace-match "#" t t)) ) (progn (goto-char (point-min)) (while (search-forward "\\brk0" nil t) (replace-match "\\\\" t t)) ) ) (setq gellmu-expansions-buff (concat gellmu-stem-name gellmu-expansions-suffix) ) (set-visited-file-name gellmu-expansions-buff) (save-buffer) (if noninteractive (progn (kill-emacs) ) ; allow interactive user to recover (setq gellmu-expansions-only nil) (fset 'gellmu-input-mode-command (intern gellmu-input-mode-command) ) (gellmu-input-mode-command) ;(exit-recursive-edit) (kill-process) ) ) () ) (if (string-equal gellmu-debug-id "expansions") (gellmu-debug-exit gellmu-write-buff) () ) ;; Insert the SGML Doctype Declaration ; ; debug-id "doctype" (setq gellmu-doctype-root-element nil) (setq gellmu-start 1) (goto-char (point-min)) ; Note: In this RE the \1 (optional) includes brackets that need ; to be stripped to form the value of the variable dtd (if (re-search-forward (concat "\\\\documenttype" gellmu-doctype-opt-regexp gellmu-doctype-arg-regexp ) nil t) (let ( ; if \documenttype TRUE (dtx "")(dtroot "")(dtsys "")(dtkey nil)(dtass ())(drass ())(dtinfo "") (dttype "")(dtfpi "")(dturl "")(dtopen "")(dtil 0)(drassl 0)(dtline "") (dtpbpair t)(encoding "")(rootatts "")) ; dtpbpair true if the doctype has a preamble/body pair defined ; this is true if there is a key of length 3 ; OR if the old way of doing things appears to apply ; so it is false if and only if there is a key of length 1 (setq gellmu-start (match-end 0)) (setq dtroot (match-string 2)) (setq gellmu-doctype-root-element dtroot) (setq dtx (match-string 1)) (replace-match "" t t) ; insert later if needed (12-May-2001) ;; 2000-Jul-01: dtx is now either a key for gellmu-doctype-info ;; or else, as originally, a SYSTEM identifier ; ; Assemble the tail of a " 0 (setq dtkey (elt (cdr drass) 0)) (cond ((= drassl 3) (setq gellmu-preamble-tag (elt (cdr drass) 1)) (setq gellmu-body-tag (elt (cdr drass) 2)) )) ) (setq dtpbpair nil) ) ) ; end of: have drass ) (if (not (and drass dtkey (stringp dtkey))) (if (not (string-equal gellmu-dtd-name "")) (progn (setq dtsys gellmu-dtd-name) ; use public variable as a SYSTEM id (setq dtline (concat "SYSTEM \"" dtsys "\"")) (setq dtkey nil) ) ) ) ) ; end of code for case where \documentype has no option ) ; end of if dtx -- is there an option for \documenttype ; code for computing dtline from dtkey ; (gellmu-message "Is dtkey present?") ; TDbg (if (and dtkey (not (string-equal dtkey ""))) (progn ; (gellmu-message "Yes") ; TDbg (setq dtass (assoc dtkey gellmu-doctype-info)) (if dtass (setq dtinfo (cdr dtass))) (if (and dtass dtinfo) (progn ; dtkey is a key for gellmu-doctype-info (if (not (listp dtinfo)) (error "Elisp error: symbol dtinfo is not a list") ) (setq dtil (length dtinfo)) (cond ((< 0 dtil) (if (string-equal (elt dtinfo 0) "xml") (setq gellmu-xml-strict t) ) (cond ((= dtil 1) (setq dtline " ")) ((= dtil 3) (setq dttype (elt dtinfo 1)) (setq dtsys (elt dtinfo 2)) (setq dtline (concat dttype " \"" dtsys "\""))) ((= dtil 4) (setq dttype (elt dtinfo 1)) (setq dtfpi (elt dtinfo 2)) (setq dtsys (elt dtinfo 3)) (setq dtline (concat dttype " \"" dtfpi "\" \"" dtsys "\""))) ((= dtil 5) ; necessarily xml (setq dttype (elt dtinfo 1)) (setq dtfpi (elt dtinfo 2)) (setq dtsys (elt dtinfo 3)) (setq encoding (elt dtinfo 4)) (setq dtline (concat dttype " \"" dtfpi "\" \"" dtsys "\""))) ((= dtil 6) ; necessarily xml (setq dttype (elt dtinfo 1)) (setq dtfpi (elt dtinfo 2)) (setq dtsys (elt dtinfo 3)) (setq encoding (elt dtinfo 4)) (setq rootatts (elt dtinfo 5)) (setq dtline (concat dttype " \"" dtfpi "\" \"" dtsys "\""))) ) )) ) ; end of dtkey is a key (progn ; (setq dtsys dtkey) ; dtkey is a SYSTEM id for a DTD (if (string-equal gellmu-preamble-tag "") (setq gellmu-preamble-tag "preamble")) (if (string-equal gellmu-body-tag "") (setq gellmu-body-tag "body")) (setq dtline (concat "SYSTEM \"" dtkey "\"")) ) ) ) ) ; (gellmu-message "XML mode test") ; TDbg (if gellmu-xml-strict (progn (if (not (string-equal encoding "")) (setq gellmu-xml-introducer (concat "") ) ) (if (not gellmu-hold-xml-introducer) (setq dtopen gellmu-xml-introducer) ) ) ) ; (gellmu-message "Test on writing DOCTYPE declaration") ; TDbg (if (not (string-equal dtline "")) ; new 20140116 ; (setq dtopen (concat dtopen "") (setq eagend (point)) (goto-char eagstart) (delete-char 1) ; the inserted "{" (goto-char eagend) ) (goto-char eagstart) (forward-char) (error "Cannot find closing brace for %s" sgmltag) ) ) ; end of while search-forward ; Check that all of this is within the [,] pair. (goto-char isustart) (backward-char 1) (if (gellmu-balance-pair-forward ?\[ 1) (progn (setq gellmu-internal-end (point)) (setq isuend (1- (point))) ; isuend is before the "]" (goto-char isustart) (while (search-forward "\\%" isuend t) (replace-match "%" t t) (setq isuend (1- isuend)) ) (setq gellmu-internal-end (1+ isuend)) ; after the "]" ; The handling of '\', '{', '}' in the internal subset is ; more complicated, and done elsewhere. ) (error "Lost closing bracket for the internal declaration subset" ) ) ; end of if gellmu-balance-pair-forward ) ; end of case internal subset exists ) ; end of if-found internal declaration subset ; Do we need to write ">" to close a DOCTYPE declaration? (if (not (string-equal dtline "")) (progn (goto-char gellmu-internal-end) (insert ">") ) ) ; insert the root tag ; (gellmu-message "Insert root tag") ; TDbg (if (and (not gellmu-regular-sgml) (not (string-equal gellmu-stem-name "")) ) (insert ; if TRUE ---> advanced gellmu (concat "<" dtroot " stem=\"" gellmu-stem-name "\">" ; ... no provision for other rootatts with advanced gellmu ) ) ; if FALSE ---> basic GELLMU (if (not (string-equal rootatts "")) (let ((ndtroot "")) (setq ndtroot (concat dtroot " " rootatts)) (setq dtroot ndtroot) ) ) (insert (concat "<" dtroot ">" ) ) ) ; (gellmu-message "Documenttype handling done") ; TDbg (setq gellmu-start (point)) (if (string-equal gellmu-debug-id "doctype") (gellmu-debug-exit gellmu-write-buff) () ) ;; Check for a gellmu-body-name zone unless gellmu-regular-sgml ; ; debug-id "preamble" (goto-char gellmu-start) (if (and (not gellmu-regular-sgml) (not gellmu-doc-fragment)) (progn (setq gellmu-tmp-str (concat "\\begin{" gellmu-body-name "}")) (if (search-forward gellmu-tmp-str nil t) (progn (setq gellmu-latex-body t) ) ; have gellmu-body-name zone (setq gellmu-latex-body nil) ) ; end of check for gellmu-body-name zone ) ) ;; Check for LaTeX emulation (if (and (not (string-equal gellmu-body-name "")) gellmu-latex-body (not dtpbpair) ) (error "The command \"%s\" is required for key \"%s\"." gellmu-body-name dtkey ) ) ) ;; end of if re-search-forward "\documenttype" TRUE ; (if gellmu-doc-fragment ; code new 20021019 (if (and gellmu-doc-fragment (not gellmu-regular-sgml)) ; new 20021029 (setq gellmu-latex-body t) ; (setq gellmu-regular-sgml nil) ; new 20021029 ) ;; large-if-FALSE ) ;; end of if re-search-forward "\documenttype" (if (string-equal gellmu-debug-id "preamble") (gellmu-debug-exit gellmu-write-buff) () ) ;; Character and small string substitutions after loc gellmu-start ; ; If one of these is going to be resolved to "\command{ ...", ; ; then it needs to be here. ALSO we need to translate such ; ; things at this stage to non-abbreviated GELLMU since we ; ; have yet to convert the chars '<' and '>'. ; ; If a string is going to be resolved to "\command;", then it ; ; should be before that but after the code for "\command{..."; ; ; this will protect CDATA in attributes arguments. ; If gellmu-latex-body is true, then ; the Character "$": used in GELLMU for toggling math zones ; "$"-delimited math zones are equiv. to ("\tmath{...}"). ; It's up to the SGML DTD where one of these can be placed. ; Replace "\$" with "\dol;" and then "$" with "\tmath{" OR "}" ; ("tmath" is the default value of gellmu-dollarmath-name.) ; ; debug-id "smallstring" (goto-char gellmu-start) (while (search-forward "\\$" nil t) (replace-match "\\dol;" t t)) (goto-char gellmu-start) (if (and gellmu-latex-body (not gellmu-regular-sgml)) (progn ; gellmu-latex-body TRUE (setq gellmu-dol-zone 0) (while (search-forward "$" nil t) (if (zerop gellmu-dol-zone) (progn (setq gellmu-dol-zone 1) (setq gellmu-dol-orig (point)) ; (replace-match "\\tmath{" t t) (replace-match (concat "\\" gellmu-dollarmath-name "{") t t) ) (let ((thislen 0) (thisstr "")) (setq thisstr (buffer-substring gellmu-dol-orig (point))) (if (string-match "\n\n" thisstr) (progn (gellmu-message "Preceding ") (what-line) (error "$-delimited math zone contains blank line -- use \\( ... \\) instead" ) ) ) (setq thislen (- (point) gellmu-dol-orig)) (if (> thislen gellmu-dol-maxlength) (progn (gellmu-message "Preceding ") (what-line) (error "$-delimited math zone too long -- use \\( ... \\) instead" ) ) ) (setq gellmu-dol-zone 0) (replace-match "}" t t) ) ; end of let ) ; end of if zerop gellmu-dol-zone ) ; end of search-forward "$" ; no more unescaped '$' characters -- are we balanced? (if (not (zerop gellmu-dol-zone)) (progn (gellmu-message "At ") (what-line) (error "Unclosed $-delimited math zone" ) ) ) ) ; this next should be simply () ; segment provided for debugging 20021019 ; (let ((sa "F") (sb "F") (sc "F")) ; gellmu-latex-body FALSE ; (if gellmu-doc-fragment (setq sa "T")) ; (if gellmu-latex-body (setq sb "T")) ; (if gellmu-regular-sgml (setq sc "T")) ; (message ; "tmath: doc-fragment %s -- latex-body %s -- regular-sgml %s" ; sa sb sc) ; ) () ) ;; The Character "^": the GELLMU superscript shortref (if (not gellmu-regular-sgml) (progn (goto-char gellmu-start) ;; replace "\^" with "\crt;" (while (search-forward "\\^" nil t) (replace-match "\\crt;" t t)) (goto-char gellmu-start) ;; now replace "^{" with "\sup{" (while (search-forward "^{" nil t) (replace-match "\\sup{" t t)) (goto-char gellmu-start) ;; yell about "^ " (while (search-forward "^ " nil t) (progn (what-line) (error "Gellmu: unattached \"^\"; use \"\\^\"." ) ) ) ; finally replace RE "\^\(.\)" with rep-RE "\sup{\1}" (goto-char gellmu-start) ;; (while (re-search-forward "\\^\\(.\\)" nil t) (replace-match "\\\\sup{\\1}" t)) )()) ;; The Character "_": the GELLMU subscript shortref ; it differs here from "^" in that it is never special in an RE (if (not gellmu-regular-sgml) (progn (goto-char gellmu-start) ; replace "\_" with "\und;" (while (search-forward "\\_" nil t) (replace-match "\\und;" t t)) (goto-char gellmu-start) ;; now replace "_{" with "\sub{" (while (search-forward "_{" nil t) (replace-match "\\sub{" t t)) (goto-char gellmu-start) ;; yell about "_ " (while (search-forward "_ " nil t) (progn (what-line) (error "Gellmu: unattached \"_\"; use \"\\_\".") ) ) ; finally replace RE "_\(.\)" with rep-RE "\sub{\1}" (goto-char gellmu-start) ;; (while (re-search-forward "_\\(.\\)" nil t) (replace-match "\\\\sub{\\1}" t)) )()) ;; Two Character String Commands (must precede "\begin{zone}" section) ; Well, we had to do "\\" long ago. ;; The String "\(": GELLMU shorthand for begin inline math mode (if (not gellmu-regular-sgml) (progn (goto-char gellmu-start) ;; replace "\(" with "\math{" (while (search-forward "\\(" nil t) (replace-match "\\math{" t t)) )()) ;; The String "\)": GELLMU shorthand for end inline math mode (if (not gellmu-regular-sgml) (progn (goto-char gellmu-start) ;; replace "\)" with "}" (while (search-forward "\\)" nil t) (replace-match "}" t t)) )()) ;; The String "\[": GELLMU shorthand for begin displaymath mode (if (not gellmu-regular-sgml) (progn (goto-char gellmu-start) ;; replace "\[" with "\displaymath{" (while (search-forward "\\[" nil t) (replace-match "\\displaymath{" t t)) )()) ;; The String "\]": GELLMU shorthand for end displaymath mode (if (not gellmu-regular-sgml) (progn (goto-char gellmu-start) ;; replace "\]" with "}" (while (search-forward "\\]" nil t) (replace-match "}" t t)) )()) ;; The String "\-": GELLMU shorthand for hyphenation guidance (if (not gellmu-regular-sgml) (progn (goto-char gellmu-start) ;; replace "\-" with "\hy0;" (while (search-forward "\\-" nil t) (replace-match "\\hy0;" t t)) )()) ;; The String "\/": shorthand for LaTeX "italic correction" (if (not gellmu-regular-sgml) (progn (goto-char gellmu-start) ;; replace "\/" with "\iTc" (someday?) (while (search-forward "\\/" nil t) (replace-match "\\iTc;" t t)) )()) ;; The String "\@": shorthand for LaTeX space adjustment (if (not gellmu-regular-sgml) (progn (goto-char gellmu-start) ;; replace "\@ with "\aTs;" (while (search-forward "\\@" nil t) (replace-match "\\aTs;" t t)) )()) ;; The String "\,": GELLMU shorthand for narrow horizontal space (if (not gellmu-regular-sgml) (progn (goto-char gellmu-start) ;; replace "\," with "\hsp;" (while (search-forward "\\," nil t) (replace-match "\\hsp;" t t)) )()) ;; The String "\ ": GELLMU shorthand a blank space (deprecated) (if (not gellmu-regular-sgml) (progn (goto-char gellmu-start) ;; replace "\ " with "\spc;" (while (search-forward "\\ " nil t) (replace-match "\\spc;" t t)) )()) ;; Automated quophrase -- this intercepts later command without ;; argument code for replacement of `` with \ldq; and '' with \rdq; (if (and gellmu-latex-body (not gellmu-regular-sgml) (not (string-equal gellmu-quophrase-name "")) ) (let ( (qzo gellmu-start) (qzb 0) (qzc 0) (qze 0) (qmsg "") (nbp t) (ibp t) ) (goto-char gellmu-start) (while (search-forward "``" nil t) (setq qzb (match-beginning 0)) (setq qzc (1+ qzb)) (setq qze 0) (setq qzo qzb) (setq nbp t) (while nbp ; first balance the inner layer to catch apostrophes (goto-char qzc) (if (gellmu-balance-pair-forward ?\` 1) (if (string-match "\\W" (char-to-string (char-after))) (if (eq (char-after) ?\') ; what non-word character follows? (progn ; full balance at hand (backward-char) (delete-char 2) (insert "}") (goto-char qzb) (delete-char 2) (insert (concat "\\" gellmu-quophrase-name "{")) (setq nbp nil) ; to break from the innermost while ) (progn ; treat as miscellaneous right single-quote (backward-char) (delete-char 1) (setq qze (1+ qze)) (insert "\\rsq;") ) ) (progn ; recyle the while nbp loop after inserting apostrophe ; (gellmu-dbmessage "quophrase: bpf, word char. follows") (backward-char) (delete-char 1) (setq qze (1+ qze)) (insert gellmu-apostrophe-tag) ; treat as apostrophe ) ) ; end of if string-match "\\W" (let ( (here 0) ) (setq here (point)) (goto-char qzo) (what-line) (goto-char here) (setq qmsg (format "Document quophrase logic violated at %d Either make sure that each \"``\" is balanced by a later \"''\" or else disable this logic by setting gellmu-quophrase-name to \"\" " qzo ) ) (gellmu-message qmsg) (if (< 0 qze) (progn (setq qmsg (format " WARNING: Zone has %d loose \"'\" characters. " qze ) ) (gellmu-message qmsg) ) ) (setq nbp nil) ; to break from while nbp (goto-char (point-max)) ; to obstruct more of this search-forward ) ) ; end of if gellmu-balance-pair-forward ?\` ) ; end of while nbp ) ; end of while search-forward "``" ) ; end of let for quophrase processing ) ; end of if for quophrase processing ;; Automated squophrase -- this intercepts later command without ;; argument code for replacement of `` with \ldq; and '' with \rdq; ; ; only if gellmu-squophrase-name is not "" (if (and gellmu-latex-body (not gellmu-regular-sgml) (not (string-equal gellmu-squophrase-name "")) ) (let ( (qzo gellmu-start) (qzb 0) (qze 0) (qmsg "") (nbp t) ) (goto-char gellmu-start) (while (search-forward "`" nil t) ; (gellmu-dbmessage "squophrase: found `") (setq qzb (match-beginning 0)) (setq qze 0) (setq qzo qzb) (setq nbp t) ; flag meaning a balance is needed (while nbp (goto-char qzb) (if (gellmu-balance-pair-forward ?\`) (if (string-match "\\W" (char-to-string (char-after))) (progn ; (gellmu-dbmessage "squophrase: bpf with whitespace") (backward-char) (delete-char 1) (insert "}") (goto-char qzb) (delete-char 1) (insert (concat "\\" gellmu-squophrase-name "{")) (setq nbp nil) ; to break from the innermost while ) (progn ; recyle the while nbp loop after removing this balance ; (gellmu-dbmessage "squophrase: bpf, NO whitespace") (backward-char) (delete-char 1) (setq qze (1+ qze)) (insert gellmu-apostrophe-tag) ; treat as apostrophe ) ) (let ( (here 0) ) (setq here (point)) (goto-char qzo) (what-line) (goto-char here) (setq qmsg (format "Document squophrase logic violated at %d Make sure that any \"`\" is balanced by a \"'\" or else set gellmu-squophrase-name to \"\" (which is the default) " qzo ) ) (gellmu-message qmsg) (if (< 0 qze) (progn (setq qmsg (format " WARNING: Zone has %d loose \"'\" characters. " qze ) ) (gellmu-message qmsg) ) ) (setq nbp nil) ; to break from the innermost while (goto-char (point-max)) ; to obstruct search-forward ) ) ; end of if-balance-pair-forward ?\` ; (gellmu-dbmessage "squophrase: nbp loop") ) ; end of while nbp ) ; end of while search-forward "`" ) ; end of let for squophrase processing ) ; end of if for squophrase processing decision (if (string-equal gellmu-debug-id "smallstring") (gellmu-debug-exit gellmu-write-buff) () ) ;; Next: watch for things dangerous in SGML... ;; What we do here needs to be BEFORE we write any SGML tags. ;; Change: <= to \leq; ;; >= to \geq; ;; =< to \leq; ;; =< to \geq; ;; Then: < to \ltc; ;; > to \gtc; ; Note: `&' is a command; we'll come to that later before doing ; "\command;" conversions. Meanwhile, we are not going to ; create `&' here. ; ; debug-id "sgmldanger" (if (not gellmu-regular-sgml) (progn (goto-char gellmu-start) (while (re-search-forward "\\([^<]\\)<=" nil t) (replace-match "\\1\\\\leq;" t) ) )()) (if (not gellmu-regular-sgml) (progn (goto-char gellmu-start) (while (re-search-forward "\\([^>]\\)>=" nil t) (replace-match "\\1\\\\geq;" t) ) )()) (if (not gellmu-regular-sgml) (progn (goto-char gellmu-start) (while (re-search-forward "\\([^=]\\)=<" nil t) (replace-match "\\1\\\\leq;" t) ) )()) (if (not gellmu-regular-sgml) (progn (goto-char gellmu-start) (while (re-search-forward "\\([^=]\\)=>" nil t) (replace-match "\\1\\\\geq;" t) ) )()) (goto-char gellmu-start) (while (re-search-forward "\\([^<]\\)<" nil t) ;(replace-match "\\1\\\\ltc;" t) (if gellmu-regular-sgml (replace-match "\\1<" t) (replace-match "\\1\\\\ltc;" t) ) ) (goto-char gellmu-start) (while (re-search-forward "\\([^>]\\)>" nil t) ;(replace-match "\\1\\\\gtc;" t) (if gellmu-regular-sgml (replace-match "\\1>" t) (replace-match "\\1\\\\gtc;" t) ) ) ;; The Character "/" "\sol;" ; Replacing this must not interfere with later SGML use. ; We've got to do it before we begin writing SGML element ; end tags. Or we could just leave it alone. ;; Hmmm... Let's try leaving '/' alone. Save work with \attr{} ;; Ummm... No. Its shorttag use means that it needs protection ;; for SGML; otherwise the first '/' inside an element ;; ends that element. (Other instances are OK, I think.) (if (not gellmu-no-auto-sol) (progn (goto-char gellmu-start) (while (search-forward "/" nil t) (replace-match "\\sol;" t t)) (if (string-equal gellmu-debug-id "sgmldanger") (gellmu-debug-exit gellmu-write-buff) () ) ) () ) ; ; debug-id "processinginst" (goto-char (point-min)) (let ( (procstart 0) (procend) ) (while (search-forward (concat "\\" gellmu-procinst-name "{") nil t) (replace-match (concat "<\?") t t) (setq procstart (point)) (insert "{") (backward-char 1) (if (gellmu-balance-pair-forward ?{ 1) (progn (delete-backward-char 1) (insert "\?>") (setq procend (point)) (goto-char procstart) (delete-char 1) ; the inserted "{" (goto-char procend) ) (goto-char procstart) (forward-char) (error "Cannot find closing brace for %s" gellmu-procinst-name) ) ) ) (if (string-equal gellmu-debug-id "processinginst") (gellmu-debug-exit gellmu-write-buff) () ) ;; Convert Matching "\begin{zone}" and "\end{zone}" ; ; to matching "\zone{" and "}", subject to further conversion ; ; later. ; ; debug-id "beginend" (goto-char gellmu-start) (while (search-forward "\\begin{" nil t) (setq gellmu-loop-pos (point)) ; (backward-char 7) ; back to start of "\begin" (goto-char (match-beginning 0)) ; back to start of "\begin" (setq gellmu-tmp-pos (point)) (if (search-forward "}" nil t) () ; no need to code if-true here since if-false bails out (progn (goto-char gellmu-tmp-pos) (what-line) (error "Gellmu: no \"}\" to balance \"\\begin{\"") ) ) (setq gellmu-tmp-str (buffer-substring gellmu-tmp-pos (point)) ) (if ; gellmu-command-regexp was once "[A-Za-z][0-9A-Za-z]*\\*?" ;(string-match "\\\\begin{\\([A-Za-z][0-9A-Za-z]*\\*?\\)}" gellmu-tmp-str) ;(string-match "\\\\begin{\\([A-Za-z][0-9A-Za-z]*\\)}" gellmu-tmp-str) (string-match (concat "\\\\begin{\\(" gellmu-command-regexp "\\)" ) gellmu-tmp-str ) () ; if-false bails out (progn (goto-char gellmu-tmp-pos) (what-line) (error "Incorrect use of \"\\begin{...}\"") ) ) ; We need to know that this match is at position 0 in gellmu-tmp-str. ; gellmu-tmp-str is the string from loc gellmu-tmp-pos to (point). (if (zerop (match-beginning 0)) (let ( (tsa "") (tsb "") (tsc "") (tsm "") (psn 0) (tch 0) ) (setq tsm (match-string 1 gellmu-tmp-str)) (if (and (string-equal tsm gellmu-body-name) (not (string-equal gellmu-body-tag "")) ) (setq tsa gellmu-body-tag) (setq tsa tsm) ) (setq tsc (concat "\\" tsa ":")) ; to form "\zone:" (ult. "") (setq tch (char-after (point))) ; an integerized char or nil (if tch () (error "Gellmu: internal -- char nil at point %d" (point)) ) (if (integerp tch) () (error "Gellmu: internal -- char not integerized at point %d" (point)) ) ; Pre-pend "b0" to "zone" to signal that "\zone" is derived ; from "\begin{zone}"; for processing the "\zone" we shall ; then know that "\zone:" is in place but that everything in ; any ao-list, even of length 1 beginning with an arg, needs ; to get ag0/op0 tags. (if (or (char-equal tch ?\{) (char-equal tch ?\[)) (setq tsb (concat "\\b0" tsa)); ao-list, write "\b0zone" ; Change 20000817 ; (setq tsb (concat "\\" tsa " ")) ; no aolist, write "\zone " (setq tsb (concat "\\" tsa "%")) ; no aolist, write "\zone%" ) ; in the latter case we'll NOT later go through "\zone{...}" stuff (setq psn (point)) ; right after "\begin{zone}" in buffer (goto-char gellmu-tmp-pos) (if (search-forward gellmu-tmp-str psn t) (replace-match tsb t t) (what-line) (error "Gellmu: internal error, lost a saved match for %s" gellmu-tmp-str) ) (if (search-forward (concat "\\end{" tsm "}") nil t) (replace-match tsc t t) (progn (goto-char gellmu-tmp-pos) (what-line) (error "Gellmu: No \"\\end\" for \"\\begin{%s}\"" tsm) ) ) ) ; end of if-zerop TRUE (the use of "\begin" was legitimate) (progn (goto-char gellmu-tmp-pos) (what-line) (error "Gellmu: Improper use command \"\\begin\"") ) ; end of if-zerop FALSE ) ; (goto-char gellmu-loop-pos) (goto-char gellmu-tmp-pos) ) ; end of code for "\begin{zone} ... \end{zone}" ;; Check for any stray strings matching the RE "\\end[^0-9A-Za-z]" (goto-char gellmu-start) (if (re-search-forward "\\\\end[^0-9A-Za-z]" nil t) (progn (what-line) (error "Illegal or unmatched command \"%s\"" (match-string 0) ) ) () ; OK ) (if (string-equal gellmu-debug-id "beginend") (gellmu-debug-exit gellmu-write-buff) () ) ; (error "\\begin{zone}...\\end{zone} subs are done") ;; Replace \command{...} with ... if there ; is no chaining of args/opts. If there is a chain, then ; generate ; ...... . . . ..., ; where "xx0" stands either for "ag0", or "op0" ; to the end of the chain and do not write an end-tag for ; . In this case will need to have dtd-spec ; as non-empty with optional end tag. If "\command" arises ; from "\begin{zone}...\end{zone}", then there will be ; an end-tag supplied from "\command:". That is, ; "\begin{zone}[...]{...}...\end{zone}" should become ; "\zone[...]{...} . . . \zone:". ; It does not matter except for ; user diagnosis if these end tags are placed in nested order. ; But user diagnosis is not trivial. ; ; ; Progress incrementally forward from gellmu-start looking for ; "\command{...}", replacing by .... After ; each match, resume at the location following "\command{" in ; order to be able to pick up nested such things. (We are not ; operating recursively since this is just dumb transliteration. ; ; debug-id "command" (goto-char gellmu-start) (setq gellmu-loopct 0) ; New Jun-2000: SGML attribute handling. If the first arg/opt ; is an option whose first character is ':', then the rest of the ; content of the option is regarded as a sequence of formal SGML ; attribute specs and accordingly is entered inside the opentag. ; But if we are doing this, then we need to be very careful about ; things such as \sol; = inside attribute values. For that ; should we allow the direct coding of attributes ONLY when automatic ; translations here such as '/' ---> '\sol;' are disabled? This is ; reasonable since (1) there is nothing in classical LaTeX that really ; corresponds to attribute value strings and (2) there is no SGML ; tradition of using empty elements for characters which can by default ; be handled as SGML PCDATA. ; BEGIN SEXP for "\command{...}" i.e., ao-command handling (let ((tagc ?>)) (while (re-search-forward gellmu-tot-re nil t) ; ca. 200 lines (setq gellmu-complex-tag nil) (setq gellmu-closetag-flag nil) (setq gellmu-soleoptonly-flag nil) (setq gellmu-autoclose-flag nil) (if (match-string 1) ; found b0 -- it came from "\begin{zone}[{[]" (progn (setq gellmu-closetag-flag t) ; We already made "\zone:" (endtag), (setq gellmu-complex-tag t) ; and "\zone" (opentag) is NOT followed ; by a blank. )()) (setq gellmu-aolist nil) ; initialize arg/opt list for each command (setq gellmu-curr-ops (match-string 3)) ; presumably "{" or "[" (setq gellmu-tmem (assoc gellmu-curr-ops gellmu-sc-list)) (if gellmu-tmem (setq gellmu-curr-opc (cdr gellmu-tmem)) ; presumably ?{ or ?\[ (error "Gellmu: (internal) bal-char part of matched string not on list: %s" gellmu-curr-ops) ) (setq gellmu-tmp-pos (point)) ; end of RE "\\\(command\)\(\[\|{\)" (setq gellmu-loopct (1+ gellmu-loopct)); ao-command serial for debugging (setq gellmu-curr-elt (match-string 2)) ; Replace "\command" with "". But first ; see if we are in an arg/opt chain. The string "[:" immediately ; after "\command" indicates an attribute list and should not be ; considered an option for the aolist. Also if gellmu-regular-sgml ; is set, the character "[" immediately after "\command" indicates ; an attribute list (since LaTeX-like options are alien to SGML). ; The "" goes after the end of the chain of brace/bracket ; balanced zones. (replace-match (concat "<" gellmu-curr-elt ">" gellmu-curr-ops) t t) ; Point is now after the "{" or "[". Check for attributes. If present, ; attributes need to be inserted with a preceding " " before the ">". ; attribute-marker 1 (if (and (= (char-before) ?\[) (or gellmu-regular-sgml (= (char-after) ?:) ) ) (progn ; have attribute list, point after "[" and maybe before ":" (backward-char) ; point between ">" and "[" (setq gellmu-tmp-pos (point)) ; between ">" and "[" (gellmu-balance-pair-forward ?\[ 2) ; point after "]" at end of ; attribute list (delete-backward-char 1) ; remove the "]" (if (= (char-after) ?\;) ; is this a defined-empty tag? (progn (delete-char 1) ; remove the ";" (insert gellmu-sgml-emptytag-close) ; which defaults to "/>" ) (insert ">") ; simple opentag closing after the attribute list ) (setq gellmu-tmp-tmp (point)) ; location after the opentag close (goto-char gellmu-tmp-pos) ; point between ">" and "[" (delete-backward-char 1) ; take out the ">" (insert " ") ; ensure space after the tag name and restore position (delete-char 1)(setq gellmu-tmp-tmp (1- gellmu-tmp-tmp)) ; remove "[" (if (= (char-after) ?:) (progn (delete-char 1) (setq gellmu-tmp-tmp (1- gellmu-tmp-tmp)) ) ) (goto-char gellmu-tmp-tmp) ; point after the ">" ) ; end of attribute list handling (progn ; no attribute list (backward-char) ; point is now after the ">" ) ) ; end of if to check whether we have an attribute list (setq gellmu-tmp-pos (point)) ; attribute-marker 2 ; ; build gellmu-aolist from present value of () (which is same as nil) (while ; grab any arg/opts into aolist (progn (setq gellmu-ltmp (point)) (setq gellmu-ctmp (char-after gellmu-ltmp)) (setq gellmu-stmp (char-to-string gellmu-ctmp)) (setq gellmu-tmem (assoc gellmu-stmp gellmu-st-list)) gellmu-tmem ) ; this progn is the while-test ; ; an aolist entry is a two item list (location tag-name) ; ; where ; ; tag-name is "ag0" or "op0" ; ; location is where the corresponding "{" or "[" is found ; add to list (setq gellmu-aolist (cons (cons gellmu-ltmp (cdr gellmu-tmem)) gellmu-aolist) ) ; is there another to add to list? (if (gellmu-balance-pair-forward gellmu-ctmp 1) () ; we can continue (progn (goto-char gellmu-ltmp) (error "Gellmu: aolist construction") (forward-char) ) ) ) ; end of while to grab additonal args/opts ;;Diagnostics: ; (gellmu-message (format "Current elt: %s" gellmu-curr-elt)) ; (setq zz-aolist gellmu-aolist) ; (while (< 0 (length zz-aolist)) ; (format "Item %d " (length zz-aolist)) ; (setq zz-tmem (car zz-aolist)) ; (format " %d %s\n" (car zz-tmem) (cdr zz-tmem)) ; (setq zz-aolist (cdr zz-aolist)) ; ) ; Now we have aolist complete with balancing verified. (if gellmu-autoclose-regexp (if (string-match gellmu-autoclose-regexp gellmu-curr-elt) (setq gellmu-autoclose-flag t) ) ) (if (< 1 (length gellmu-aolist)) (setq gellmu-complex-tag t) ; case of length >= 2 (if ; case of length 1 (and (not gellmu-closetag-flag) ; (string-equal gellmu-curr-ops "\[") ; gellmu-curr-ops is wrong (string-equal "op0" (cdr (car gellmu-aolist))) ) (progn ; input usage such as \item[some opt] ... -- no auto end-tag (setq gellmu-soleoptonly-flag t) ) ) ) ; Work backward. On the one hand, aolist is LIFO and, on the ; other hand, our buffer changes while working backward will not ; mess up location values later in the list (earlier in the ; buffer. (while (< 0 (length gellmu-aolist)) (setq gellmu-tmem (car gellmu-aolist)) ; last list member (setq gellmu-aolist (cdr gellmu-aolist)) ; shorten the list (setq gellmu-ltmp (car gellmu-tmem)) ; location of arg/opt (setq gellmu-stmp (cdr gellmu-tmem)) ; either "ag0" or "op0" (goto-char gellmu-ltmp) ; go to arg/opt beginning (setq gellmu-ctmp (char-after gellmu-ltmp)) (if (gellmu-balance-pair-forward gellmu-ctmp 1) ; span this {ao-value} (progn ; zone-close-char found (setq gellmu-ktmp (point)) ; {ao-value} is from ltmp to ktmp ; Shall we write a close-tag for the entire command element? (if (or gellmu-closetag-flag ; already have a close-tag gellmu-complex-tag ; there could be further content gellmu-soleoptonly-flag ; there could be further content ) (progn ; write a close-tag for the entire command element ; only if all of the following are true: ; (1) it's in gellmu-autoclose-list. ; (2) gellmu-closetag-flag is false. ; (3 )we don't see another tag immediately next. (if gellmu-autoclose-flag (if (not gellmu-closetag-flag) (if (= (char-after) ?\\) (progn ; author's close tag but not from begin/end (setq gellmu-closetag-flag t) ) (progn (setq gellmu-closetag-flag t) (insert (concat "")) (goto-char gellmu-ktmp) ) ) ) ) ) (progn ; write a closetag (setq gellmu-closetag-flag t) (insert (concat "")) (goto-char gellmu-ktmp) ) ) (delete-backward-char 1) ; removing the "}" or "]" ; '(*** RISKY CODE ***) ; Used "op0" literally in the next line after having put it ; in gellmu-st-list. ; Shall we surround this ao-value with ag0/op0 tags? (if (or gellmu-complex-tag (string-equal gellmu-stmp "op0")) ; '(*** end of RISKY CODE ***) (progn ; complex-tag -- insert arg/opt tags (setq gellmu-complex-tag t) ; could be a single opt (insert (concat "")) (goto-char gellmu-ltmp) (delete-char 1) ; removing the "{" or "[" (insert (concat "<" gellmu-stmp ">")) ) ; end of arg/opt tag insertion (progn ; simple-tag -- no arg/opt tags (goto-char gellmu-ltmp) (delete-char 1) ; removing the "{" or "[" ) ; end of NO arg/opt tag insertion ) ) ; end of zone-close-char found (progn (goto-char gellmu-ltmp) (error "Gellmu: internal re-balancing error on aovalue span") ) ) ) ; end of while length of gellmu-aolist > 0 )) ; END SEXP for "\command{...}". (if (string-equal gellmu-debug-id "command") (gellmu-debug-exit gellmu-write-buff) () ) ;; Look for miscellaneous zones delimited by balanced braces ; ; Balanced brackets do not count ; ; debug-id "misclatex" ; There is no sense for "lg0" in regular SGML (if (not gellmu-regular-sgml) (progn (goto-char gellmu-start) (while (search-forward "{" nil t) (setq gellmu-tmp-pos (point)) (backward-char) (if (gellmu-balance-pair-forward balbr 1) (progn (delete-backward-char 1) (insert "") (goto-char gellmu-tmp-pos) (delete-backward-char 1) (insert "") ) (progn (goto-char gellmu-tmp-pos) (error "Gellmu: Unbalanced miscellaneous open brace \"{\"" ) ) ) ))()) ;; Here we do char/small string replacements going to "\command;" ;; Things involving quotes of any kind, whether LaTeX-like or not ; ; potentially dangerous in many places ;; The Character '"' (keyboard-double-quote): "\quo;" ; Hmmm... What about SGML processors down the road looking for ; CDATA in attribs? It might be better to leave this conversion ; for them to handle rather than to reverse engineer. Of course, ; the same statement applies to "=" and "%" in URLs, ... ; So a processor looking for CDATA needs to sanitize first. ; That processor is, in fact, better equipped to decide than we, ; who would only be guessing. Placing this conversion after ; that of commands with options and args should handle most of ; this issue. ; (goto-char gellmu-start) ; (while (search-forward "\"" nil t) ; (replace-match "\\quo;" t t)) ;; The String "``": "\ldq;", the left double quote ; ; With some document one cannot simply ; ; go through replacing ``, '' pairs with \quophrase{} ; ; because there may be a deliberate lack of balance. ; ; If \quophrase is meant, it should be used; it may be OK to let ; ; the author's editing environment map '"' to \quophrase, however, ; ; since the author will be able to spot trouble. (if (not gellmu-regular-sgml) (progn (goto-char gellmu-start) ;; replace "``" with "\ldq;" (while (search-forward "``" nil t) (replace-match "\\ldq;" t t)) )) ;; The string "''''", cf., unicode character U-2057 (if (not gellmu-regular-sgml) (progn (goto-char gellmu-start) ;; replace "''''" with "\rqq;" (while (search-forward "''''" nil t) (replace-match "\\rqq;" t t)) )) ;; The string "'''", cf., unicode character U-2034 (if (not gellmu-regular-sgml) (progn (goto-char gellmu-start) ;; replace "'''" with "\rtq;" (while (search-forward "'''" nil t) (replace-match "\\rtq;" t t)) )) ;; The String "''": "\rdq;", the right double quote (if (not gellmu-regular-sgml) (progn (goto-char gellmu-start) ;; replace "''" with "\rdq;" (while (search-forward "''" nil t) (replace-match "\\rdq;" t t)) )) ;; The Character "`" (keyboard-back-quote): "\lsq;" (if (not gellmu-regular-sgml) (progn (goto-char gellmu-start) ;; replace "`" with "\lsq;" (while (search-forward "`" nil t) (replace-match "\\lsq;" t t)) )) ; ;; The Character "'" (keyboard-single-quote): "\rsq;" ; (if (not gellmu-regular-sgml) (progn ; (goto-char gellmu-start) ;; replace "'" with "\rsq;" ; (while (search-forward "'" nil t) ; (replace-match "\\rsq;" t t)) ; )) ;; The Character "'" (apostrophe or keyboard-single-quote): ;; "\apos;" or "\rsq;" ;; use \rsq if the ff. character is not a word character ;; (if (not gellmu-regular-sgml) (let ((thematch nil)) (goto-char gellmu-start) ;; (while (search-forward "'" nil t) (setq thematch (match-data)) (if (string-match "\\W" (char-to-string (char-after))) (progn (set-match-data thematch) (replace-match "\\rsq;" t t) ) (progn (set-match-data thematch) (replace-match "\\apos;" t t) ) ) ) )) ;;; At this point if we're NOT thinking at all like LaTeX, ; ; having handled '%', '\', '{', '}', much of this other ; ; code should be revised. So maybe this should be a ; ; "do-latex" zone split out as a non-independent function. ; ; ; ; Added 1-Jul-2000: it now *is* handled with the variable ; ; gellmu-regular-sgml but not as a separate zone or function. ; ; ; ; Another parallel such function might be "do-sgml" for ; ; using Gellmu to author DECLs and DTDs. !! ?? ; ; ; ; Hmmm... will the gellmu-regular-sgml be good for editing ; ; the GELLMU version of a DTD under "boot.dtd"? ; ; ;;; And what to do about LaTeX-isms such as "\'", "\,", ... ? ;; The String "\%"; "\pct;" (if (not gellmu-regular-sgml) (progn (goto-char gellmu-start) ;; change "\%" to "\pct;" (while (search-forward "\\%" nil t) (replace-match "\\pct;" t t)) ) (progn ; regular-sgml ; but '%' is still a comment introducer (goto-char gellmu-start) ;; change "\%" to "%" (while (search-forward "\\%" nil t) (replace-match "%" t t)) ) ) ;; The character "&" ;; Needs SGML protection if not opening an entity reference (if (not gellmu-regular-sgml) (progn ; ; The Character "&": used as tabular cell separator in LaTeX ; ; Here, however, gellmu-tab-amp is required to generate ; ; gellmu-tab-cell (which so far is not used much) (goto-char gellmu-start) ;; replace "\&" with "\amp;" (while (search-forward "\\&" nil t) (replace-match "\\amp;" t t)) (goto-char gellmu-start) ;; replace, e.g., "& " with "\tabampcell " ;(while (search-forward gellmu-tab-amp nil t) ; (replace-match (concat "\\" gellmu-tab-cell) t t)) ; Note: gellmu-tab-amp-re has one marked expression (while (re-search-forward gellmu-tab-amp-re nil t) (replace-match (concat "\\" gellmu-tab-cell (match-string 1)) t t) ) ) (progn ; regular sgml ; "\&" required only if if "&" is followed (goto-char gellmu-start) ;; replace "\&" with "&" (while (search-forward "\\&" nil t) (replace-match "&" t t)) (goto-char gellmu-start) ;; replace "&" with "&" if not entity ref (while (re-search-forward "&\\([^#A-Za-z]\\)" nil t) (replace-match "&\\1" t)) ) ) ;; The Character "~": the GELLMU non-breaking inter-word space ;; Hmmm... what about in "\attr{}" ? (if (not gellmu-no-auto-nbs) (progn (goto-char gellmu-start) ;; replace "\~" with "\tld;" (while (search-forward "\\~" nil t) (replace-match "\\tld;" t t)) (goto-char gellmu-start) ;; replace "~" with "\nbs;" (while (search-forward "~" nil t) (replace-match gellmu-nbs-repn t t)) ) () ) ;; The String "---": "\pdash;", "punctuation dash" --- as used here (if (not gellmu-regular-sgml) (progn (goto-char gellmu-start) ;; replace "---" with "\pdash;" (while (search-forward "---" nil t) (replace-match "\\pdash;" t t)) )()) ;; The String "--": "\rdash;", "range dash", e.g. as in "4--17" (if (not gellmu-regular-sgml) (progn (goto-char gellmu-start) ;; replace "--" with "\rdash;" (while (search-forward "--" nil t) (replace-match "\\rdash;" t t)) )()) ;; Need to handle longer strings first ;; The Character "-" "\hyp;" -- need to handle "--" and "---" first (if (not gellmu-regular-sgml) (progn (goto-char gellmu-start) ;; replace "-" with "\hyp;" (while (search-forward "-" nil t) (replace-match "\\hyp;" t t)) )()) ;; The string "\@." \aos;" -- LaTeX-math @-end-of-sentence ; ; An SGML processor can worry about whether this is in math ; ; mode or not and whether it cares. (LaTeX cares.) (goto-char gellmu-start) (while (search-forward "\\@." nil t) (replace-match "\\aos;" t t)) ;; The string "\@?" \aoq;" -- LaTeX-math @-end-of-question ; ; An SGML processor can worry about whether this is in math ; ; mode or not and whether it cares. (LaTeX cares.) (goto-char gellmu-start) (while (search-forward "\\@?" nil t) (replace-match "\\aoq;" t t)) ;; The string "\@!" \aoe;" -- LaTeX-math @-end-of-exclamation ; ; An SGML processor can worry about whether this is in math ; ; mode or not and whether it cares. (LaTeX cares.) (goto-char gellmu-start) (while (search-forward "\\@!." nil t) (replace-match "\\aoe;" t t)) ; If you end a sentence with normal sentence-ending punctuation ; followed by two white space characters, GELLMU will record an ; appropriate end-of-sentence mark. ;; The RE "\.\({^j}\| \)" --> "\eos;\1", the end-of-sentence. ; Here the '{^j}' represents a newline; see the code just below. ; This provides a means of handling end-of-sentence ; inside "displaymath". (if (not gellmu-regular-sgml) (progn (goto-char gellmu-start) (while (re-search-forward "\\.\\(\n\\| \\)" nil t) (replace-match "\\\\eos;\\1" t)) )()) ;; The RE "?\({^j}\| \)" --> "\eoq;\1", the end-of-question. ; Can we test this? New sentence? Not a new sentence. (if (not gellmu-regular-sgml) (progn (goto-char gellmu-start) (while (re-search-forward "?\\(\n\\| \\)" nil t) (replace-match "\\\\eoq;\\1" t)) )()) ;; The RE "!\({^j}\| \)" --> "\eoe;\1", the end-of-exclamation. ; Can we test this! New sentence! Not a new sentence. (if (not gellmu-regular-sgml) (progn (goto-char gellmu-start) (while (re-search-forward "!\\(\n\\| \\)" nil t) (replace-match "\\\\eoe;\\1" t)) )()) (if (string-equal gellmu-debug-id "misclatex") (gellmu-debug-exit gellmu-write-buff) () ) ;; "Special" characters ; Aside from obvious special characters such as '\', '{', '}', '<', ; '>', '&', ... there are other characters that require special ; attention. For *presentation* XML one may write them as CDATA ; entities. But for more sophisticated XML (or SGML), when a ; character is one of these or is special in a translation target ; or in a formatting target, there are issues of delayed evaluation. ; Now that most CPU's have more than 256 KB of RAM the best way to ; handle these things is as defined-empty XML (or SGML) elements. ; The defined-empty element
in HTML is almost but not quite an ; example. ; ; For "advanced gellmu", with a large number of LaTeX-like features, ; among the ASCII characters, anything other than the digits (0-9), ; and the letters (A-za-z) can be special. Whether it is depends ; on the document type and the list of translation and formatting ; targets. ; ; It seems to be sensible to use three letter codes for these. ; Example: the character '=' is represented this way by the ; empty element in the didactic GELLMU document type. ; This code might systematically replace all instances of "=" ; with "", or it could leave discretion with the author ; on the question of whether to use "=" or (in GELLMU source) ; "\eqc;". Actually '=' is translated here to "" and in ; the didactic GELLMU production system's translation to XML ; it is translated to one of "", "", or "=", ; depending on its context relative to the didactic document type. ; ; The point is that no respectable XML (or SGML) processor wants ; to go looking through ordinary character data for "=". So if ; the author might *ever* want something different done with "=" ; than simple expression as "=" -- for example "=" ; (Aha! Well, that probably should come from "".), ; then the representation as a defined-empty element is a good thing. ; ; In the didactic GELLMU document type the defined-empty character ; elements (but not "", which is forced newline) are allowed ; where ordinary characters are allowed. ; ; Note that rolling out a CDATA character entity "&eqc;" would ; not be any different from the direct use of "=" in those locales ; where "=" is a directly accessible character. ; ; debug-id "nonstdchars" (if (not gellmu-regular-sgml) (progn ; case: advanced gellmu = not regular SGML ;; The Character "!" "\exc;" ; ; For XML translate to "" in math zones, '!' otherwise (goto-char gellmu-start) (while (search-forward "!" nil t) (replace-match "\\exc;" t t) ) ;; The Character "@" "\atc;" -- "@" is never "other" for GELLMU ;; Protect "@" so we can code toward Texinfo (goto-char gellmu-start) (while (search-forward "@" nil t) (replace-match "\\atc;" t t)) ;; The Character "#" "\hsh;" (goto-char gellmu-start) (while (search-forward "\\#" nil t) (replace-match "\\hsh;" t t)) (goto-char gellmu-start) ; (while (search-forward "#" nil t) (while (re-search-forward "[^&]#" nil t) (progn (what-line) (send-string-to-terminal (format "Warning: Loose '#'\n") ) ) ) ;; The Character "*" "\ast;" ; ; If we allow "\command*", check if this needs to be later. (let ((tagc ?>)) (goto-char gellmu-start) (while (search-forward "*" nil t) (if (char-equal (char-after (point)) tagc) () ; do nothing if "*" is in ; '>' must now be markup (replace-match "\\ast;" t t) ) )) ;; The Character "+" "\plu;" ; ; With the didactic GELLMU production system '+' is sometimes ; ; used in writing LaTeX as boundary marker for LaTeX's \verb ; ; At other times '|' is so used. For this reason "\plu;" is ; ; needed. (goto-char gellmu-start) (while (search-forward "+" nil t) (replace-match "\\plu;" t t) ) ;; The Character "|" "\vbr;" (goto-char gellmu-start) (while (search-forward "|" nil t) (replace-match "\\vbr;" t t) ) ;; The Character "=" "\eqs;" ; ; In the didactic GELLMU production system '\eqs;' is translated ; ; for XML to "" in regular zones, to "" in math ; ; and back to "=" inside certain "meta" zones. (goto-char gellmu-start) (while (search-forward "=" nil t) (if (not (= (char-after) ?\")) (replace-match "\\eqs;" t t) ) ) ) ; end of case: advanced gellmu = not regular SGML () ) (if (string-equal gellmu-debug-id "nonstdchars") (gellmu-debug-exit gellmu-write-buff) () ) ;; Replace "\command;" with "" ;; Replace "\command:" with "" (mainly for "\end{zone}") ;; Replace "\command%" (without argument) with "" ;; Anything else comes from bad source for strict XML ;; If not strict XML, replace other "\command." with "." ; ; debug-id "loosetag" (goto-char gellmu-start) (while (re-search-forward "\\\\\\([A-Za-z][0-9A-Za-z]*\\*?\\)\\([^0-9A-Za-z*]\\)" nil t ) ; changed to allow *-names (setq gellmu-tmp-str (match-string 2)) ; A switch would be cleaner here (if (string-equal gellmu-tmp-str ";") ; case: ";" (replace-match (concat "<\\1" gellmu-sgml-emptytag-close) t nil) (progn ; not ";" (if (string-equal gellmu-tmp-str ":") (replace-match "" t nil) ; case: ":" (progn ; neither ";" nor ":" (if (string-equal gellmu-tmp-str "%") (replace-match "<\\1>" t nil) ; case: "%" (progn ; neither ";" nor ":" nor "%" (if gellmu-xml-strict (progn (what-line) (send-string-to-terminal (format "WARNING: Possible unbalanced opentag in XML: %s\n" (match-string 1) ) ) ) ) ; end of if-gellmu-xml-strict (if (string-equal gellmu-tmp-str "\\") (replace-match "<\\1>\\\\" t nil) ; case: "\\" (replace-match "<\\1>\\2" t nil) ; everything else ) ; end of if-"\\" ) ; end of neither ";" nor ":" nor "%" ) ; end of if-"%" ) ; end of neither ";" nor ":" ) ; end of if-":" ) ; end of not-";" ) ; end of if-";" (backward-char 1) ; back toward the match-end, necessary? ) ;; end of code for "\command" without argument (if (string-equal gellmu-debug-id "loosetag") (gellmu-debug-exit gellmu-write-buff) () ) ; Almost everything looks like SGML at this point. ; Hmmm... do we have any stray backslashes at hand now? ;; Blank Input Lines ; A blank line preceding LaTeX traditional command names for ; block level commands ; will NOT be considered shortref for new-paragraph since it ; would be redundant. Before one of these if a new paragraph is ; wanted, it must be explicit, i.e., "" or "", ; the latter not requiring a close-tag. ; ; debug-id "parb" (goto-char gellmu-start) ;; PARB first marker (if (not gellmu-no-parb)(progn (if gellmu-parb-everywhere () ; allow parb (if (search-forward (concat "<" gellmu-body-tag ">") nil t) () ; allow parb (error "Have PARB enabled without having command \"%s\"\nto spawn the tag \"<%s>\"" gellmu-body-name gellmu-body-tag ) ) ) (while ;; the blank-line-game -- code to "prepare" blank lines (re-search-forward gellmu-parb-regexp nil t) (setq gellmu-debug-garbage (match-string 0)) ; ; Make sure that there are no completely blank lines in here (let ((eil 0)(vil 0)) (setq gellmu-tmp-il-loc (match-beginning 0)) (setq eil (match-end 0)) (goto-char gellmu-tmp-il-loc) (setq vil eil) (while (search-forward "\n" vil t) (replace-match "\t\n") (setq eil (1+ eil)) ; now update the forward location "vil" (setq vil eil) ) ) ; ; replace each mandatory newline in gellmu-parb-regexp with "\t\n" ; ; in order to block "parb" insertion there ; ; Ummm ... What about the non-mandatory newlines? (goto-char (1- gellmu-tmp-il-loc)) (if (re-search-forward gellmu-parb-regexp nil t) ; (replace-match "\t\n\\1\t\n\\3<\\4\\5" t) (replace-match "\t\n\\1\t\n\\3<\\4\\5\\6" t) (goto-char gellmu-tmp-il-loc) (what-line) (error "Gellmu internal error: match vanished\n string: %s\n" gellmu-debug-garbage ) ) ) ;; end of the blank-line-game (goto-char gellmu-start) ;; now to insert 's (if gellmu-parb-everywhere () ; fine (if (search-forward (concat "<" gellmu-body-tag ">") nil t) () ; have moved forward to body (error "GELLMU internal logical error: lost gellmu-body-tag") ) ) (while ;;; next search string adjusted to accomodate new tagging for "\foo;" (re-search-forward gellmu-misc-re-a nil t) (replace-match (concat "\\1\n<" gellmu-parb-name ">\n\\3") t) ) ;; Take out any tags that landed after (goto-char gellmu-start) (if gellmu-parb-everywhere () ; don't take out any (if (search-forward (concat "") nil t) () ; moved forward to point after end of body (gellmu-message (format "WARNING: Document lacks closetag \"\"" gellmu-body-tag) ) ) (while (search-forward (concat "<" gellmu-parb-name ">") nil t) (replace-match "" t) ) ) )) ;; PARB second marker (if (string-equal gellmu-debug-id "parb") (gellmu-debug-exit gellmu-write-buff) () ) ;; For regular SGML clean up "", "", and "" ; ; The handling of these three is now sufficiently parallel to make ; ; it efficient here to do one pass; but will it stay this way? ; ; These names should never show up as author tag names or as tags ; ; in a classic dtd with "basic GELLMU" (gellmu-regular-sgml true) (if gellmu-regular-sgml (let ( (sbsl (concat "") ) (gellmu-message (format "Gellmu: -- WARNING: Output has no DOCTYPE declaration." ) ) ) ) ;; Record version information as a comment (goto-char (point-max)) (insert "\n" ) ; ; Go to Beginning of the Write-Buffer ;; Purge TABS again (goto-char (point-min)) (while (search-forward "\t" nil t) (replace-match "" t t)) ;; Purge end-of-line blank spaces (goto-char (point-min)) (while (re-search-forward " +$" nil t) (replace-match "" t t)) ;; Comment out, SGML-style, anything between (point-min) and ;; gellmu-start. (This will destroy all location values.) (goto-char (point-min)) (let ((thisre "")) (setq thisre (concat "\\(" (regexp-quote gellmu-xml-introducer) "\\)?" (regexp-quote "") (goto-char (point-min)) (insert "