diff -C 2 -r -P openjade-1.3/style/jade_version.h openjade-1.3-starlink-0.1/style/jade_version.h
*** openjade-1.3/style/jade_version.h	Thu Oct 14 23:00:35 1999
--- openjade-1.3-starlink-0.1/style/jade_version.h	Tue Feb 29 11:06:48 2000
***************
*** 1 ****
! #define JADE_VERSION SP_T("1.3")
--- 1 ----
! #define JADE_VERSION SP_T("1.3-starlink-0.1")
diff -C 2 -r -P openjade-1.3/README.latex openjade-1.3-starlink-0.1/README.latex
*** openjade-1.3/README.latex	Thu Jan  1 01:00:00 1970
--- openjade-1.3-starlink-0.1/README.latex	Tue Feb 29 11:04:58 2000
***************
*** 0 ****
--- 1,25 ----
+ 
+ This is a patched version of Jade, which adds a back-end which
+ generates portable LaTeX, in the spirit of the SGML Transformation
+ back-end.  The patches should be applied against a distribution copy
+ of openjade-1.3.tar.
+ 
+ The changes consist of:
+ 
+  - The addition of the files jade/LaTeX*, and suitable edits elsewhere
+    in that directory;
+  - Updating the version number in style/jade_version.h
+  - Adding documentation in the form of jadedoc/latex.htm
+  - Edits to the configure script to enable support for the new
+    back-end.
+ 
+ To build:
+ 
+     ./configure --enable-latex
+     make
+ 
+ 
+ Norman Gray
+ http://www.astro.gla.ac.uk/users/norman/
+ 8 February 2000
+ 
diff -C 2 -r -P openjade-1.3/config/configure.in openjade-1.3-starlink-0.1/config/configure.in
*** openjade-1.3/config/configure.in	Wed Sep  1 08:25:58 1999
--- openjade-1.3-starlink-0.1/config/configure.in	Tue Feb 29 11:05:23 2000
***************
*** 2,6 ****
  dnl  configure.in
  dnl
! AC_REVISION($Id: configure.in,v 1.8.4.2 1999/09/01 07:25:58 clasen Exp $)
  dnl
  dnl  Process this file with autoconf to produce a configure script.
--- 2,6 ----
  dnl  configure.in
  dnl
! AC_REVISION($Id: configure.in,v 1.2 2000/02/29 11:05:23 norman Exp $)
  dnl
  dnl  Process this file with autoconf to produce a configure script.
***************
*** 152,155 ****
--- 152,168 ----
      AC_MSG_RESULT(no))
  
+ 
+ dnl
+ dnl  Simple LaTeX support
+ dnl  (added by norman@astro.gla.ac.uk, 19990514)
+ dnl
+ dnl AC_ARG_ENABLE(latex,
+ dnl [  --enable-latex          bind in support for LaTeX-Transform output],
+ dnl     if test $enableval
+ dnl     then
+ dnl 	AC_DEFINE(JADE_LATEX)
+ dnl     fi)
+ 
+ 
  dnl
  dnl  optional backends
***************
*** 157,160 ****
--- 170,174 ----
  smr_SWITCH(mif, support for FrameMaker MIF output, on, JADE_MIF)
  smr_SWITCH(html, support for HTML+CSS output, on, JADE_HTML)
+ smr_SWITCH(latex, support for LaTeX-Transform output, on, JADE_LATEX)
  
  
diff -C 2 -r -P openjade-1.3/jade/LaTeXFOTBuilder.cxx openjade-1.3-starlink-0.1/jade/LaTeXFOTBuilder.cxx
*** openjade-1.3/jade/LaTeXFOTBuilder.cxx	Thu Jan  1 01:00:00 1970
--- openjade-1.3-starlink-0.1/jade/LaTeXFOTBuilder.cxx	Tue Feb 29 11:05:59 2000
***************
*** 0 ****
--- 1,743 ----
+ // LaTeXFOTBuilder.cxx: a backend for Jade which emits LaTeX code,
+ // for subsequent processing by vanilla LaTeX (ie, not jadetex).
+ //
+ // This file heavily based on (read, simplified from) TransformFOTBuilder.cxx
+ //
+ // Written by Norman Gray <norman@astro.gla.ac.uk>
+ // Copyright (c) 2000 Norman Gray
+ 
+ #include "config.h"
+ #include "LaTeXFOTBuilder.h"
+ //#include "LaTeXMessages.h"
+ #include "FOTBuilder.h"
+ #include "OutputCharStream.h"
+ #include "MessageArg.h"
+ #include "ErrnoMessageArg.h"
+ 
+ #include <errno.h>
+ 
+ #ifdef DSSSL_NAMESPACE
+ namespace DSSSL_NAMESPACE {
+ #endif
+ 
+ const char RE = '\r';
+ 
+ class LaTeXFOTBuilder : public SerialFOTBuilder {
+ public:
+   // LaTeX output
+   struct CommandNIC {
+     ~CommandNIC();
+     StringC name;
+     Vector<StringC> parameters;
+   };
+   struct EnvironmentNIC {
+     ~EnvironmentNIC();
+     StringC name;
+     Vector<StringC> brackets;
+     Vector<StringC> parameters;
+     StringC reControl;
+   };
+   class LaTeXExtensionFlowObj : public FOTBuilder::ExtensionFlowObj {
+   public:
+     virtual void atomic(LaTeXFOTBuilder &, const NodePtr &) const = 0;
+   };
+   class LaTeXCompoundExtensionFlowObj : public FOTBuilder::CompoundExtensionFlowObj {
+   public:
+     virtual void start(LaTeXFOTBuilder &, const NodePtr &) const = 0;
+     virtual void end(LaTeXFOTBuilder &) const = 0;
+   };
+   class EmptyCommandFlowObj : public LaTeXExtensionFlowObj {
+     void atomic(LaTeXFOTBuilder &fotb, const NodePtr &nd) const {
+       if (nic_.name.size() > 0)
+ 	fotb.latexCommand(nic_, false);
+       else {
+ 	// Make a command of the same name as the current element's GI
+ 	// Is this a good idea?
+ 	GroveString str;
+ 	CommandNIC tem(nic_);
+ 	tem.name = fotb.makeStringC("UnknownCommand");
+ 	if (nd && nd->getGi(str) == accessOK) {
+ 	  fotb.insertOptString(tem.parameters, str);
+ 	  //tem.name.assign(str.data(), str.size());
+ 	  fotb.latexCommand(tem, false);
+ 	}
+ 	else
+ 	  // Can't find a GI - I'm really _not_ sure this is a good idea!
+ 	  fotb.latexCommand(nic_, false);
+       }
+     }
+     bool hasNIC(const StringC &name) const {
+       return name == "name" || name == "parameters";
+     }
+     void setNIC(const StringC &name, const Value &value) {
+       switch (name[0]) {
+        case 'n':
+ 	value.convertString(nic_.name);
+ 	break;
+        case 'p':
+ 	value.convertStringList(nic_.parameters);
+ 	break;
+       }
+     }
+     ExtensionFlowObj *copy() const { return new EmptyCommandFlowObj(*this); }
+   private:
+     CommandNIC nic_;
+   };
+   class CommandFlowObj : public LaTeXCompoundExtensionFlowObj {
+     void start(LaTeXFOTBuilder &fotb, const NodePtr &nd) const {
+       if (nic_.name.size() > 0)
+ 	fotb.latexCommand(nic_, true);
+       else {
+ 	GroveString str;
+ 	CommandNIC tem(nic_);
+ 	tem.name = fotb.makeStringC("UnknownCommand");
+ 	if (nd && nd->getGi(str) == accessOK) {
+ 	  fotb.insertOptString(tem.parameters, str);
+ 	  //tem.name.assign(str.data(), str.size());
+ 	  fotb.latexCommand(tem, true);
+ 	}
+ 	else
+ 	  fotb.latexCommand(nic_, true);
+       }
+     }
+     void end(LaTeXFOTBuilder &fotb) const {
+       fotb.endLatexCommand();
+     }
+     bool hasNIC(const StringC &name) const {
+       return name == "name" || name == "parameters";
+     }
+     void setNIC(const StringC &name, const Value &value) {
+       switch (name[0]) {
+        case 'n':
+ 	value.convertString(nic_.name);
+ 	break;
+        case 'p':
+ 	value.convertStringList(nic_.parameters);
+ 	break;
+       }
+     }
+     ExtensionFlowObj *copy() const { return new CommandFlowObj(*this); }
+   private:
+     CommandNIC nic_;
+   };
+   class EnvironmentFlowObj : public LaTeXCompoundExtensionFlowObj {
+     void start(LaTeXFOTBuilder &fotb, const NodePtr &nd) const {
+       if (nic_.name.size() > 0)
+ 	fotb.startEnvironment(nic_);
+       else {
+ 	GroveString str;
+ 	EnvironmentNIC tem(nic_);
+ 	tem.name = fotb.makeStringC("UnknownEnvironment");
+ 	if (nd && nd->getGi(str) == accessOK) {
+ 	  fotb.insertOptString(tem.parameters, str);
+ 	  //tem.name.assign(str.data(), str.size());
+ 	  fotb.startEnvironment(tem);
+ 	}
+ 	else {
+ 	  fotb.startEnvironment(tem);
+ 	}
+       }
+     }
+     void end(LaTeXFOTBuilder &fotb) const {
+       fotb.endEnvironment();
+     }
+     bool hasNIC(const StringC &name) const {
+       return name == "name" || name == "parameters" ||
+ 	name == "brackets" || name == "recontrol";
+     }
+     void setNIC(const StringC &name, const Value &value) {
+       switch (name[0]) {
+        case 'n':
+ 	value.convertString(nic_.name);
+ 	break;
+        case 'p':
+ 	value.convertStringList(nic_.parameters);
+ 	break;
+        case 'b':
+ 	value.convertStringList(nic_.brackets);
+ 	break;
+        case 'r':
+ 	value.convertString(nic_.reControl);
+ 	break;
+       }
+     }
+     ExtensionFlowObj *copy() const { return new EnvironmentFlowObj(*this); }
+   private:
+     EnvironmentNIC nic_;
+   };
+   class EntityFlowObj : public LaTeXCompoundExtensionFlowObj {
+     void start(LaTeXFOTBuilder &fotb, const NodePtr &) const {
+       fotb.startEntity(systemId_);
+     }
+     void end(LaTeXFOTBuilder &fotb) const {
+       fotb.endEntity();
+     }
+     bool hasNIC(const StringC &name) const {
+       return name == "system-id";
+     }
+     void setNIC(const StringC &name, const Value &value) {
+       value.convertString(systemId_);
+     }
+     ExtensionFlowObj *copy() const { return new EntityFlowObj(*this); }
+   private:
+     StringC systemId_;
+   };
+   LaTeXFOTBuilder(CmdLineApp *);
+   ~LaTeXFOTBuilder();
+   void startEnvironment(const EnvironmentNIC &);
+   void endEnvironment();
+   void latexCommand(const CommandNIC &, bool);
+   void endLatexCommand();
+   void startEntity(const StringC &);
+   void endEntity();
+   void characters(const Char *s, size_t n);
+   void charactersFromNode(const NodePtr &, const Char *, size_t);
+   void extension(const ExtensionFlowObj &fo, const NodePtr &);
+   void formattingInstruction(const StringC &);
+ 
+   // Non-extension flow-objects
+   void startParagraph(const ParagraphNIC &);
+   void endParagraph();
+   //void setParagraphNIC(const ParagraphNIC &);
+ 
+   void startExtensionSerial(const CompoundExtensionFlowObj &fo, const NodePtr &nd);
+   void endExtensionSerial(const CompoundExtensionFlowObj &fo);
+   void start();
+   void end();
+   StringC LaTeXFOTBuilder::makeStringC(const char *s);
+   void LaTeXFOTBuilder::insertOptString(Vector<StringC> &arr, GroveString str);
+   void setEscapeTeX(bool);
+ 
+ private:
+   LaTeXFOTBuilder(const LaTeXFOTBuilder &);
+   void operator=(const LaTeXFOTBuilder &);
+ 
+   OutputCharStream &os() { return *os_; }
+   void parameters(const Vector<StringC> &params);
+   // Support removed from TransformFOTBuilder
+   // flushPendingRe(): not needed - space is gen. less significant in LaTeX 
+ 
+   CmdLineApp *app_;
+   OutputCharStream *os_;
+   Owner<OutputCharStream> topOs_;
+   struct environmentState {
+     ~environmentState();
+     StringC str;
+     bool isEnv;
+     bool reBefore, reMiddle, reEnd;
+   };
+   //Vector<StringC> openEnvironments_;
+   Vector<environmentState> openEnvironments_;
+   StringC undefGi_;
+   struct OpenFile : Link {
+     ~OpenFile();
+     OutputCharStream *saveOs;
+     // fb must be before os so it gets destroyed afterwards
+     FileOutputByteStream fb;
+     Owner<OutputCharStream> os;
+     StringC systemId;
+   };
+   IList<OpenFile> openFileStack_;
+   bool midLine_;
+   bool escapeTeX_;
+   bool internalREs_;
+   // internalREs_ controls whether routines below can freely insert REs
+   // where allowed by LaTeX.  Currently, it merely shadows escapeTeX_.
+   // If escapeTeX_ is false, the style is possibly
+   // generating some sort of `verbatim' environment, where it wouldn't want
+   // this code monkeying with the line-breaking.  Perhaps solve this by
+   // making ReControl (or similar) be an inherited characteristic like
+   // escapeTeX_
+ 
+   // really Vector<bool> (I'm copying this from TransformFOTBuilder.cxx!)
+   StringC escapeTeXStack_;
+   void message(const MessageType0 &);
+ };
+ 
+ FOTBuilder *makeLaTeXFOTBuilder(CmdLineApp *app,
+ 				const FOTBuilder::Extension *&ext)
+ {
+   static const LaTeXFOTBuilder::EmptyCommandFlowObj emptycommand;
+   static const LaTeXFOTBuilder::CommandFlowObj command;
+   static const LaTeXFOTBuilder::EnvironmentFlowObj environment;
+   static const LaTeXFOTBuilder::EntityFlowObj entity;
+   static const FOTBuilder::Extension extensions[] = {
+     {
+       "UNREGISTERED::Norman Gray//Flow Object Class::environment",
+       0,
+       0,
+       0,
+       0,
+       &environment
+     },
+     {
+       "UNREGISTERED::Norman Gray//Flow Object Class::command",
+       0,
+       0,
+       0,
+       0,
+       &command
+     },
+     {
+       "UNREGISTERED::Norman Gray//Flow Object Class::empty-command",
+       0,
+       0,
+       0,
+       0,
+       &emptycommand
+     },
+     {
+       "UNREGISTERED::James Clark//Flow Object Class::entity",
+       0,
+       0,
+       0,
+       0,
+       &entity
+     },
+     {
+       "UNREGISTERED::Norman Gray//Characteristic::escape-tex?",
+       (void (FOTBuilder::*)(bool))&LaTeXFOTBuilder::setEscapeTeX,
+       0,
+       0,
+       0,
+       0,
+     },
+     { 0 }
+   };
+   ext = extensions;
+   return new LaTeXFOTBuilder(app);
+ }
+ 
+ static
+ void outputNumericCharRef(OutputCharStream &os, Char c)
+ {
+   os << "\\char" << (unsigned long)c << ' ';
+ }
+ 
+ LaTeXFOTBuilder::LaTeXFOTBuilder(CmdLineApp *app)
+ : app_(app),
+   topOs_(new RecordOutputCharStream(app->makeStdOut())),
+   escapeTeX_(1), internalREs_(1)
+ {
+   undefGi_ = app_->systemCharset().execToDesc("#UNDEF");
+   topOs_->setEscaper(outputNumericCharRef);
+   os_ = topOs_.pointer();
+   escapeTeXStack_ += 0;
+ }
+ 
+ LaTeXFOTBuilder::~LaTeXFOTBuilder()
+ {
+ }
+ 
+ static bool contains(const StringC &str, Char c)
+ {
+   for (size_t i = 0; i < str.size(); i++)
+     if (str[i] == c)
+        return 1;
+   return 0;
+ }
+ 
+ // Insert %+RE where possible, and when internalREs_ is true.
+ void LaTeXFOTBuilder::parameters(const Vector<StringC> &params)
+ {
+   for (size_t i = 0; i < params.size(); i ++) {
+     // If the parameter starts with ?, it's written as an optional
+     // parameter, after stripping the ?.  If it starts with !, it's written
+     // as a required parameter (thus allowing you to start parameter values 
+     // with ?.   Otherwise, it's written as a required parameter.
+     size_t len = params[i].size();
+     const Char *s = params[i].data();
+     bool optional;
+     if (i != 0 && internalREs_)
+     {
+       os() << '%' << RE;
+       midLine_ = false;
+     }
+ 
+     if (*s == '?')
+     {
+       optional = true;
+       s++;
+       len--;
+     } else if (*s == '!') {
+       optional = false;
+       s++;
+       len--;
+     } else
+       optional = false;
+ 
+     os() << (optional ? '[' : '{');
+     midLine_ = true;
+     characters(s, len);
+     os() << (optional ? ']' : '}');
+     midLine_ = true;
+   }
+ }
+ 
+ // Should internalREs_ override the default here?
+ void LaTeXFOTBuilder::startEnvironment(const EnvironmentNIC &nic)
+ {
+   environmentState env;
+   if (nic.reControl.size() == 3) {
+     env.reBefore = (nic.reControl[0] == '/');
+     env.reMiddle = (nic.reControl[1] == '/');
+     env.reEnd    = (nic.reControl[2] == '/');
+   }
+   else {
+     env.reBefore = false;
+     env.reMiddle = true;
+     env.reEnd = false;
+   }
+   if (nic.brackets.size() == 2) {
+     os() << nic.brackets[0];
+     env.str = nic.brackets[1];
+     env.isEnv = false;
+     openEnvironments_.push_back(env);
+   }
+   else {
+     const StringC &s = nic.name.size() == 0 ? undefGi_ : nic.name;
+     if (env.reBefore && midLine_)
+       os() << RE;
+     os() << "\\begin";
+     if (env.reMiddle)
+       os() << RE;
+     os() << '{';
+     midLine_ = true;
+     characters(s.data(), s.size());
+     os() << '}';	// os() << '{' << s << '}';
+     if (env.reEnd)
+     {
+       os() << RE;
+       midLine_ = false;
+     } else
+       midLine_ = true;
+     parameters(nic.parameters);
+     env.str = s;
+     env.isEnv = true;
+     openEnvironments_.push_back (env);
+   }
+   start();
+ }
+ 
+ void LaTeXFOTBuilder::latexCommand(const CommandNIC &nic, bool hasContent)
+ {
+   const StringC &s = nic.name.size() == 0 ? undefGi_ : nic.name;
+   os() << '\\' << s;
+   if (internalREs_)
+   {
+     os() << RE;
+     midLine_ = false;
+   }
+   parameters(nic.parameters);
+   if (hasContent) {
+     os() << '{';
+     start();
+   }
+   else
+     atomic();
+ }
+ 
+ void LaTeXFOTBuilder::endLatexCommand()
+ {
+   // only called when command has content
+   os() << '}';
+   end();
+ }
+ 
+ void LaTeXFOTBuilder::endEnvironment()
+ {
+   environmentState env = openEnvironments_.back();
+   openEnvironments_.resize(openEnvironments_.size() - 1);
+   if (env.isEnv) {
+     if (env.reBefore && midLine_)
+       os() << RE;
+     os() << "\\end";
+     if (env.reMiddle)
+       os() << RE;
+     os() << '{' << env.str << '}';
+     if (env.reEnd)
+     {
+       os() << RE;
+       midLine_ = false;
+     } else
+       midLine_ = true;
+   }
+   else
+     os() << env.str;
+   end();
+ }
+ 
+ void LaTeXFOTBuilder::formattingInstruction(const StringC &s)
+ {
+   //flushPendingRe();
+   os() << s;
+ }
+ 
+ void LaTeXFOTBuilder::startEntity(const StringC &systemId)
+ {
+   //flushPendingRe();
+   OpenFile *ofp = new OpenFile;
+   openFileStack_.insert(ofp);
+   ofp->systemId = systemId;
+   ofp->saveOs = os_;
+   String<CmdLineApp::AppChar> filename;
+ #ifdef SP_WIDE_SYSTEM
+   filename = systemId;
+ #else
+   filename = app_->codingSystem()->convertOut(systemId);
+ #endif
+   if (filename.size()) {
+     filename += 0;
+     if (!ofp->fb.open(filename.data())) {
+       app_->message(CmdLineApp::openFileErrorMessage(),
+ 		    StringMessageArg(systemId),
+ 		    ErrnoMessageArg(errno));
+     }
+     else {
+       ofp->os
+ 	= new RecordOutputCharStream(
+ 	      new EncodeOutputCharStream(&ofp->fb,
+ 				         app_->outputCodingSystem()));
+       ofp->os->setEscaper(outputNumericCharRef);
+       os_ = ofp->os.pointer();
+     }
+   }
+ }
+ 
+ void LaTeXFOTBuilder::endEntity()
+ {
+   //flushPendingRe();
+   OpenFile &of = *openFileStack_.head();
+   if (of.os) {
+     errno = 0;
+     of.os->flush();
+     if (!of.fb.close())
+       app_->message(CmdLineApp::closeFileErrorMessage(),
+ 		    StringMessageArg(of.systemId),
+ 		    ErrnoMessageArg(errno));
+   }
+   os_ = of.saveOs;
+   delete openFileStack_.get();
+ }
+ 
+ inline
+ OutputCharStream &operator<<(OutputCharStream &os, GroveString &str)
+ {
+   return os.write(str.data(), str.size());
+ }
+ 
+ void LaTeXFOTBuilder::charactersFromNode(const NodePtr &nd, const Char *s, size_t n)
+ {
+   GroveString name;
+   GroveString text;
+   NodePtr entity;
+   const char quot = '"';
+ #if 0
+   if (n == 1
+       && *s == 0xFFFD
+       && nd->getEntityName(name) == accessOK
+       && nd->getEntity(entity) == accessOK
+       && entity->getText(text) == accessOK)
+     os() << "<sdata name=" << quot << Data(name.data(), name.size()) << quot
+          << " text=" << quot << Data(text.data(), text.size()) << quot
+ 	 << "/>" << RE;
+   else
+ #endif
+     LaTeXFOTBuilder::characters(s, n);
+ #if 0
+   GroveString name;
+   // If the node is an SDATA node, then emit its contents verbatim.
+   // Is this the correct thing to do?  The Transform back-end doesn't
+   // do this, but it produces what looks like a multibyte character
+   // reference when presented with SDATA entities, and that doesn't
+   // look right at all....
+   // 
+   // The following appears to work with SDATA entities in most cases,
+   // but when an SDATA entity appears in a context such as 
+   //   (element dt
+   //     (make empty-command name: "item"
+   //       parameters: (list (string-append "?" (data (current-node))))))
+   // then what actually appears is \char65533, apparently irrespective
+   // of the value of the entity.  In other words, it's very similar
+   // behaviour to the Transform back-end.  A workaround is to define
+   // the putative SDATA entities to be CDATA entities.
+   if (n == 1 && nd->getSystemData(name) == accessOK)
+     os() << name;
+   else
+     LaTeXFOTBuilder::characters(s, n);
+ #endif
+ }
+ 
+ // Write out characters, escaping TeX non-letters.  Use midLine_ to
+ // keep a little state: suppress blank lines and leading blanks (the
+ // first is necessary to avoid spurious paragraphs, the second simply
+ // seems like a Good Idea, and safe in principle).  Note that this
+ // mechanism is probably breakable, since other parts of this class
+ // write stuff to os as well. If there is a problem, then either the
+ // mechanism should be implemented within OutputCharStream (or at
+ // least within os()), or the routine shouldn't try to skip the
+ // blanks.
+ void LaTeXFOTBuilder::characters(const Char *s, size_t n)
+ {
+   if (n == 0)
+     return;
+   // Following lifted with adaptations from TeXFOTBuilder
+   for (; n > 0; n--, s++) {	// Since TeX has only 256 characters
+ 				// by default, two-byte characters
+ 				// will need special treatment.
+     if (*s > 255) {
+       // Don't complicate matters, just give the character!
+       os() << "\\char" << (unsigned long)(*s) << ' ';
+       midLine_ = true;
+     } else {			// Otherwise, check for special
+ 				// TeX escapes.
+       switch(*s) {
+        default:
+ 	os() << char(*s);
+ 	midLine_ = true;
+ 	break;
+ 
+        case ' ':
+        case '\t':
+ 	 // Don't try to suppress leading whitespace, since this pointlessly
+ 	 // complicates things (eg, it needs to be suppressed inside 
+ 	 // verbatim output).
+ 	 //if (midLine_)
+ 	 os() << ' ';
+ 	break;
+ 
+        case '\\':		// TeX special characters
+        case '^':
+        case '_':
+        case '~':
+ 	if (escapeTeX_)
+ 	  os() << "\\char" << int(*s) << "{}";
+ 	else
+ 	  os() << char(*s);
+ 	midLine_ = true;
+  	break;
+ 
+        case '{':
+        case '}':
+        case '$':
+        case '&':
+        case '#':
+        case '%':
+ 	if (escapeTeX_)
+ 	  os() << "\\" << char(*s);
+ 	else
+ 	  os() << char(*s);
+ 	midLine_ = true;
+  	break;
+ 
+        case '\r':
+        case '\n':
+ 	if (midLine_ || !escapeTeX_)
+ 	  os() << RE;
+ 	midLine_ = false;
+ 	break;
+       }
+     }
+   }
+   // No need for anything fancy here.  I stripped out the state_ mechanism
+   // from TransformFOTBuilder, because I don't think it's necessary for LaTeX
+   //os().put(*s);
+   //os().write(s, n);
+ }
+ 
+ StringC LaTeXFOTBuilder::makeStringC(const char *s)
+ {
+   StringC tem;
+   if (s)
+     while (*s)
+       tem += (unsigned char)*s++;
+   return tem;
+ }
+ 
+ void LaTeXFOTBuilder::insertOptString(Vector<StringC> &arr, GroveString str)
+ {
+   arr.resize(arr.size()+1);
+   for (size_t i=arr.size()-1; i>0; i--)
+     arr[i] = arr[i-1];
+   arr[0] = makeStringC("?");
+   arr[0].append(str.data(), str.size());
+ }
+ 
+ void LaTeXFOTBuilder::extension(const ExtensionFlowObj &fo, const NodePtr &nd)
+ {
+   ((const LaTeXExtensionFlowObj &)fo).atomic(*this, nd);
+ }
+ 
+ void LaTeXFOTBuilder::startExtensionSerial(const CompoundExtensionFlowObj &fo, const NodePtr &nd)
+ {
+   ((const LaTeXCompoundExtensionFlowObj &)fo).start(*this, nd);
+ }
+ 
+ void LaTeXFOTBuilder::endExtensionSerial(const CompoundExtensionFlowObj &fo)
+ {
+   ((const LaTeXCompoundExtensionFlowObj &)fo).end(*this);
+ }
+ 
+ void LaTeXFOTBuilder::message(const MessageType0 &msg)
+ {
+   app_->message(msg);
+ }
+ 
+ void LaTeXFOTBuilder::startParagraph(const ParagraphNIC &nic)
+ {
+   start();
+   //setParagraphNIC(nic);
+ }
+ 
+ void LaTeXFOTBuilder::endParagraph()
+ {
+   CommandNIC par;
+   par.name = makeStringC("par");
+   latexCommand(par, false);
+   end();
+ }
+ 
+ // void LaTeXFOTBuilder::setParagraphNIC(const ParagraphNIC &nic)
+ // {
+ //   setDisplayNIC(nic);
+ // }
+ 
+ void LaTeXFOTBuilder::setEscapeTeX(bool b)
+ {
+   escapeTeX_ = b;
+   internalREs_ = escapeTeX_;	// have this simply shadow escapeTeX_
+ }
+ 
+ void LaTeXFOTBuilder::start()
+ {
+   escapeTeXStack_ += Char(escapeTeX_);
+ }
+ 
+ void LaTeXFOTBuilder::end()
+ {
+   escapeTeXStack_.resize(escapeTeXStack_.size() - 1);
+   escapeTeX_ = bool(escapeTeXStack_[escapeTeXStack_.size() - 1]);
+   internalREs_ = escapeTeX_;
+ }
+ 
+ LaTeXFOTBuilder::OpenFile::~OpenFile()
+ {
+ }
+ 
+ LaTeXFOTBuilder::environmentState::~environmentState()
+ {
+ }
+ 
+ LaTeXFOTBuilder::CommandNIC::~CommandNIC()
+ {
+ }
+ 
+ LaTeXFOTBuilder::EnvironmentNIC::~EnvironmentNIC()
+ {
+ }
+ 
+ #ifdef DSSSL_NAMESPACE
+ }
+ #endif
+ 
+ #include "LaTeXFOTBuilder_inst.cxx"
diff -C 2 -r -P openjade-1.3/jade/LaTeXFOTBuilder.h openjade-1.3-starlink-0.1/jade/LaTeXFOTBuilder.h
*** openjade-1.3/jade/LaTeXFOTBuilder.h	Thu Jan  1 01:00:00 1970
--- openjade-1.3-starlink-0.1/jade/LaTeXFOTBuilder.h	Tue Feb 29 11:05:59 2000
***************
*** 0 ****
--- 1,20 ----
+ // Copyright (c) 1999 Norman Gray
+ 
+ #ifndef LaTeXFOTBuilder_INCLUDED
+ #define LaTeXFOTBuilder_INCLUDED 1
+ 
+ #include "FOTBuilder.h"
+ #include "CmdLineApp.h"
+ 
+ #ifdef DSSSL_NAMESPACE
+ namespace DSSSL_NAMESPACE {
+ #endif
+ 
+ FOTBuilder *makeLaTeXFOTBuilder(CmdLineApp *app,
+ 				const FOTBuilder::Extension *&);
+ 
+ #ifdef DSSSL_NAMESPACE
+ }
+ #endif
+ 
+ #endif /* not LaTeXFOTBuilder_INCLUDED */
diff -C 2 -r -P openjade-1.3/jade/LaTeXFOTBuilder_inst.m4 openjade-1.3-starlink-0.1/jade/LaTeXFOTBuilder_inst.m4
*** openjade-1.3/jade/LaTeXFOTBuilder_inst.m4	Thu Jan  1 01:00:00 1970
--- openjade-1.3-starlink-0.1/jade/LaTeXFOTBuilder_inst.m4	Tue Feb 29 11:05:59 2000
***************
*** 0 ****
--- 1,24 ----
+ // Copyright (c) 1997 James Clark
+ // See the file COPYING for copying permission.
+ 
+ #include "config.h"
+ 
+ #ifdef SP_MANUAL_INST
+ 
+ #define SP_DEFINE_TEMPLATES
+ #include "IList.h"
+ #include "Vector.h"
+ #undef SP_DEFINE_TEMPLATES
+ 
+ #ifdef DSSSL_NAMESPACE
+ namespace DSSSL_NAMESPACE {
+ #endif
+ 
+ __instantiate(IList<LaTeXFOTBuilder::OpenFile>)
+ __instantiate(Vector<LaTeXFOTBuilder::environmentState>)
+ 
+ #ifdef DSSSL_NAMESPACE
+ }
+ #endif
+ 
+ #endif /* SP_MANUAL_INST */
diff -C 2 -r -P openjade-1.3/jade/Makefile.sub openjade-1.3-starlink-0.1/jade/Makefile.sub
*** openjade-1.3/jade/Makefile.sub	Mon Aug 30 11:25:22 1999
--- openjade-1.3-starlink-0.1/jade/Makefile.sub	Tue Feb 29 11:05:59 2000
***************
*** 1,5 ****
  PROG=openjade
  OBJS=jade.o SgmlFOTBuilder.o RtfFOTBuilder.o HtmlFOTBuilder.o \
!   TeXFOTBuilder.o TransformFOTBuilder.o MifFOTBuilder.o
  INCLUDE=-I$(srcdir)/../grove -I$(srcdir)/../spgrove -I$(srcdir)/../style
  XLIBS=../style/libostyle.a ../spgrove/libospgrove.a ../grove/libogrove.a \
--- 1,5 ----
  PROG=openjade
  OBJS=jade.o SgmlFOTBuilder.o RtfFOTBuilder.o HtmlFOTBuilder.o \
!   TeXFOTBuilder.o TransformFOTBuilder.o MifFOTBuilder.o LaTeXFOTBuilder.o
  INCLUDE=-I$(srcdir)/../grove -I$(srcdir)/../spgrove -I$(srcdir)/../style
  XLIBS=../style/libostyle.a ../spgrove/libospgrove.a ../grove/libogrove.a \
***************
*** 7,11 ****
  GENSRCS=JadeMessages.h HtmlMessages.h RtfMessages.h TeXMessages.h \
   HtmlFOTBuilder_inst.cxx RtfFOTBuilder_inst.cxx  TeXFOTBuilder_inst.cxx \
!  TransformFOTBuilder_inst.cxx MifMessages.h MifFOTBuilder_inst.cxx
  
  HtmlFOTBuilder.o: HtmlFOTBuilder_inst.cxx HtmlMessages.h
--- 7,12 ----
  GENSRCS=JadeMessages.h HtmlMessages.h RtfMessages.h TeXMessages.h \
   HtmlFOTBuilder_inst.cxx RtfFOTBuilder_inst.cxx  TeXFOTBuilder_inst.cxx \
!  TransformFOTBuilder_inst.cxx MifMessages.h MifFOTBuilder_inst.cxx \
!  LaTeXFOTBuilder_inst.cxx
  
  HtmlFOTBuilder.o: HtmlFOTBuilder_inst.cxx HtmlMessages.h
***************
*** 14,16 ****
--- 15,18 ----
  MifFOTBuilder.o: MifFOTBuilder_inst.cxx MifMessages.h
  TransformFOTBuilder.o: TransformFOTBuilder_inst.cxx
+ LaTeXFOTBuilder.o: LaTeXFOTBuilder_inst.cxx
  jade.o: JadeMessages.h
diff -C 2 -r -P openjade-1.3/jade/jade.cxx openjade-1.3-starlink-0.1/jade/jade.cxx
*** openjade-1.3/jade/jade.cxx	Sun Oct 17 21:37:39 1999
--- openjade-1.3-starlink-0.1/jade/jade.cxx	Tue Feb 29 11:05:59 2000
***************
*** 14,17 ****
--- 14,20 ----
  #include "MifFOTBuilder.h"
  #endif
+ #ifdef JADE_LATEX
+ #include "LaTeXFOTBuilder.h"
+ #endif
  #include "OutputCharStream.h"
  #include "macros.h"
***************
*** 42,45 ****
--- 45,51 ----
                      mifType,
  #endif
+ #ifdef JADE_LATEX
+ 		    latexType,
+ #endif
                      sgmlType, xmlType };
    static const AppChar *const outputTypeNames[];
***************
*** 60,63 ****
--- 66,72 ----
    SP_T("mif"),
  #endif
+ #ifdef JADE_LATEX
+   SP_T("latex"),
+ #endif
    SP_T("sgml"),
    SP_T("xml")
***************
*** 68,71 ****
--- 77,87 ----
  {
    registerOption('t',
+ #ifdef JADE_LATEX
+ #ifdef JADE_MIF
+                  SP_T("(fot|rtf|tex|mif|latex|sgml|xml)")
+ #else
+                  SP_T("(fot|rtf|tex|latex|sgml|xml)")
+ #endif
+ #else
  #ifdef JADE_MIF
                   SP_T("(fot|rtf|tex|mif|sgml|xml)")
***************
*** 73,76 ****
--- 89,93 ----
                   SP_T("(fot|rtf|tex|sgml|xml)")
  #endif
+ #endif
  		 );
    registerOption('o', SP_T("output_file"));
***************
*** 145,148 ****
--- 162,168 ----
    case htmlType:
  #endif
+ #ifdef JADE_LATEX
+   case latexType:
+ #endif
    case sgmlType:
    case xmlType:
***************
*** 172,175 ****
--- 192,199 ----
      return makeMifFOTBuilder(outputFilename_, entityManager(), systemCharset(), this, exts);
  #endif /* JADE_MIF */
+ #ifdef JADE_LATEX
+   case latexType:
+     return makeLaTeXFOTBuilder(this, exts);
+ #endif /* JADE_LATEX */
    case fotType:
      return makeSgmlFOTBuilder(new RecordOutputCharStream(new EncodeOutputCharStream(&outputFile_,
diff -C 2 -r -P openjade-1.3/jadedoc/index.htm openjade-1.3-starlink-0.1/jadedoc/index.htm
*** openjade-1.3/jadedoc/index.htm	Sun Oct 17 21:37:40 1999
--- openjade-1.3-starlink-0.1/jadedoc/index.htm	Mon Mar 13 13:27:47 2000
***************
*** 61,64 ****
--- 61,66 ----
                      <li><a href="transform.htm"><font
                          face="Arial">SGML Transformation</font></a></li>
+ 		    <li><a href="latex.htm"><font
+ 			face="Arial">LaTeX</font></a></li>
                  </ul>
              </li>
diff -C 2 -r -P openjade-1.3/jadedoc/latex.htm openjade-1.3-starlink-0.1/jadedoc/latex.htm
*** openjade-1.3/jadedoc/latex.htm	Thu Jan  1 01:00:00 1970
--- openjade-1.3-starlink-0.1/jadedoc/latex.htm	Tue Feb 29 11:06:06 2000
***************
*** 0 ****
--- 1,220 ----
+ <!-- -*- sgml -*- -->
+ <!doctype html public "-//W3C//DTD HTML 3.2//EN">
+ <!-- $Id: latex.htm,v 1.1 2000/02/29 11:06:06 norman Exp $ -->
+ 
+ <title>Using Jade to generate LaTeX</title>
+ 
+ <body bgcolor="#ffffff">
+ <h1>Using Jade to generate LaTeX</h1>
+ 
+ <p><ul>
+ <li><a href="#fo">Flow object extensions</a>
+ <li><a href="#para">Paragraphs and white space</a>
+ <li><a href="#bug">Bugs</a>
+ </ul>
+ 
+ <p>Jade's <a href="TeX.htm">TeX back-end</a> supports (a subset of)
+ the DSSSL style language, but it requires a special version of TeX.
+ This document describes an alternative approach, using a LaTeX
+ back-end to generate arbitrary LaTeX, in the spirit of Jade's
+ <em>transformation</em> back-end.  That is, rather than doing the
+ styling within Jade, using the DSSSL style language, we transform the
+ SGML document into (more-or-less) high-level LaTeX markup, and do all
+ the formatting within LaTeX.  You can generate LaTeX using the
+ transformation back-end plus a lot of <code>(literal ...)</code>, but
+ that's rather errorprone, and has potential whitespace problems.
+ 
+ <p>This approach means that (a) you can generate LaTeX which is itself
+ distributable because it doesn't rely on a particular TeX setup, and
+ (b) you can offload the formatting magic into a LaTeX class, which
+ might be more confortable for you.  This approach runs counter to
+ DSSSL's supposedly central virtue, of generating high-quality print
+ output from a format-independent stylesheet.  However, as the SGML
+ Transformation back-end has shown, Jade and the DSSSL Style Language
+ together make a powerful general SGML processor, which needn't be
+ limited to final (ie, immediately printable) versions of documents.
+ 
+ <p>With the patched sources, the version reported by <code>jade
+ -v</code> is `<code>Jade version "1.3-starlink-0.1"</code>'
+ 
+ <h2><a name="fo">Flow object extensions</a></h2>
+ 
+ <p>The extensions described here are available in conjunction with the
+ LaTeX back-end, selected with the <code>-t latex</code> option.  This
+ requires an appropriately patched version of Jade, built with the
+ <code>--enable-latex</code> option to <code>./configure</code>.
+ 
+ <p>The extensions, the code which supports them, and even
+ this documentation, are closely based on James Clark's <a
+ href="transform.htm">SGML Transformation back-end</a> (qv).
+ 
+ <dl>
+ <dt><code>command</code> and <code>empty-command</code>
+ <dd>These flow objects result in LaTeX commands in the output.
+ <code>command</code> is a compound flow object, whilst
+ <code>empty-command</code> is an atomic flow object (it may not have
+ child flow objects).  Both flow objects have the following non-inherited
+ characteristics:
+   <dl>
+   <dt><code>name</code>
+   <dd>This is a string-valued characteristic that specifies the name
+   of the environment.  It defaults to the generic identifier of the
+   current node.
+ 
+   <dt><code>parameters</code>
+   <dd>This specifies the command's parameters as a list of
+   strings.  If the parameter string starts with a `?' character, the
+   parameter value is the remainder of the string, written as an
+   optional parameter.  If the parameter string starts with `!', it is
+   written as a required parameter, allowing you to start parameter
+   values with a `?' character.
+   <p>For example, the following would generate the documentclass line
+   at the beginning of a LaTeX file:
+   <pre>
+     (make empty-command name: "documentclass"
+ 	  parameters: (list "?a4paper" "article"))
+   </pre>
+   </dl>
+ 
+ <p>The difference between the two
+ flow objects is that the content of the <code>command</code> flow
+ object appears as the command's final parameter.  Thus, the following
+ are equivalent:
+ <pre>
+ (element em
+   (make command name: "emph"
+     (process-children)))
+ </pre>
+ and
+ <pre>
+ (element em
+   (make empty-command name: "emph"
+     parameters: (list (data (current-node)))))
+ </pre>
+ 
+ <dt><code>environment</code>
+ <dd>This flow object results in an environment in the output.  It is a
+ compound flow object (it can have child flow objects).  It has the
+ following non-inherited characteristics:
+ 
+   <dl>
+   <dt><code>name</code>
+   <dd>As for <code>command</code>
+ 
+   <dt><code>parameters</code>
+   <dd>As for <code>command</code>
+ 
+   <dt><code>brackets</code>
+   <dd>This allows you to specify explicitly what the beginning and end
+   of the environment should be.  The characteristic's value is a list
+   consisting of two strings, the first of which is inserted at the
+   beginning, and the second at the end, of the environment.  For
+   example, you might specify that an element type
+   <code>equation</code> should be transformed into a LaTeX equation
+   via a flow object constructor such as:
+   <pre>
+   (element mequation
+     (make environment brackets: '("\\[" "\\]")
+           (process-children)))
+   </pre>
+ 
+   <dt><code>recontrol</code>
+   <dd>The LaTeX generated by the back-end has line-breaks inserted to
+   avoid the lines becoming too long.  If these are inappropriate for
+   some reason, you can override the line-breaking by giving a value to
+   the <code>recontrol</code> characteristic.  Its value is a string
+   with three characters, controlling the line-breaking before, in the
+   middle of (ie, between the <code>\\begin</code> and the environment
+   name), and after the opening and closing of the environment.  If the
+   corresponding character is `/' a RE is inserted at the appropriate
+   point; if it is `-', no RE is inserted.  For example, a
+   <code>verbatim</code> element type might be supported via:
+   <pre>
+   (element verbatim
+     (make environment
+       name: "verbatim"
+       recontrol: "/-/"
+       (process-children)))
+   </pre>
+   Thus, the <code>\\begin{verbatim}</code> and
+   <code>\\end{verbatim}</code> will be on lines by themselves, with no
+   RE between the <code>\\begin</code> or <code>\\end</code> and the
+   environment name.
+ 
+   </dl>
+ 
+ </dl>
+ 
+ <p>The <code>entity</code> and <code>formatting-instruction</code>
+ flow object classes are available exactly as in the <a
+ href="transform.htm">SGML transformation back-end</a>.
+ 
+ <p>In addition, there is also the following characteristic:
+ <dl>
+ <dt><code>escape-tex?</code>
+ <dd>This is an inherited boolean characteristic.  When true (the
+ default), characters which are significant to LaTeX, such as
+ backslashes or dollar signs, are escaped on output.  If false, this
+ escaping is turned off.
+ <p>For example, the <code>verbatim</code> element type mentioned above
+ would best be implemented as:
+ <pre>
+ (element verbatim
+   (make environment
+     name: "verbatim"
+     recontrol: "/-/"
+     escape-tex?: #f
+     (process-children)))
+ </pre>
+ </dl>
+ 
+ <p>These classes must be declared using
+ <code>declare-flow-object-class</code> in any DSSSL specification that
+ makes use of them.  A suitable set of declarations is:
+ <pre>
+ (declare-flow-object-class command
+   "UNREGISTERED::Norman Gray//Flow Object Class::command")
+ (declare-flow-object-class empty-command
+   "UNREGISTERED::Norman Gray//Flow Object Class::empty-command")
+ (declare-flow-object-class environment
+   "UNREGISTERED::Norman Gray//Flow Object Class::environment")
+ (declare-characteristic escape-tex?
+   "UNREGISTERED::Norman Gray//Characteristic::escape-tex?"
+   #t)
+ </pre>
+ 
+ <h2><a name="para">Paragraphs and white space</a></h2>
+ 
+ <p>The back-end attempts to suppress redundant whitespace.  It
+ removes blank lines, because they could insert spurious paragraphs.
+ Paragraphs are delimited purely by <code>\\par</code> commands.  The
+ back-end provides minimal support for the <code>paragraph</code>
+ flow object class, so you should support paragraph elements with a
+ construction like:
+ <pre>
+ (element para
+   (make paragraph
+     (process-children)))
+ </pre>
+ 
+ <p>The suppression of blank lines is not terribly sophisticated (it should
+ really be supported at a slightly lower level than it is), and I would
+ be grateful to hear of any problems with it.  If there are problems,
+ a workaround is to insert a command <code>\\catcode`\\^^M=10</code>
+ near the beginning of the LaTeX file.  This will cause all newlines to
+ be interpreted as simple spaces, so that blank lines will no longer be
+ interpreted as delimiting paragraphs.
+ 
+ <h2><a name="bug">Bugs</a></h2>
+ 
+ <p>This is a patch to the official openjade release.  I've submitted
+ the patch to the openjade team, but unless and until it's incorporated
+ into the main distribution, any bugs in the LaTeX support should be
+ reported to me rather than to them.
+ 
+ <div align=right>
+ <p><address>
+ <a href="http://www.astro.gla.ac.uk/users/norman/" >Norman Gray</a><br>
+ 9 February 2000
+ </address>
+ </div>
