/*@externs:External Declarations:Directories and file conventions@************/
/*                                                                           */
/*  THE LOUT DOCUMENT FORMATTING SYSTEM (VERSION 3.02)                       */
/*  COPYRIGHT (C) 1994 Jeffrey H. Kingston                                   */
/*                                                                           */
/*  Jeffrey H. Kingston (jeff@cs.su.oz.au)                                   */
/*  Basser Department of Computer Science                                    */
/*  The University of Sydney 2006                                            */
/*  AUSTRALIA                                                                */
/*                                                                           */
/*  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 1, or (at your option)      */
/*  any later version.                                                       */
/*                                                                           */
/*  This program is distributed in the hope that it will be useful,          */
/*  but WITHOUT ANY WARRANTY; without even the implied warranty of           */
/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            */
/*  GNU General Public License for more details.                             */
/*                                                                           */
/*  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.                */
/*                                                                           */
/*  FILE:         externs                                                    */
/*  MODULE:       External Declarations                                      */
/*                                                                           */
/*****************************************************************************/
#include <stdio.h>
#include <string.h>

#if LOCALE_ON
#include <locale.h>
#include <nl_types.h>
extern nl_catd MsgCat;
#define condcatgets(cat, set, msg, s) catgets(cat, set, msg, s) 
#else
#define condcatgets(cat, set, msg, s) s
#endif


/*****************************************************************************/
/*                                                                           */
/*  Include, font and database directories, and the DEBUG_ON and ASSERT_ON   */
/*  flags (defined by -D options on the cc command line in the makefile).    */
/*                                                                           */
/*  LATIN               Non-zero means compile for ISO-LATIN-1 char set.     */
/*  INCL_DIR            The system directory where @Include files are kept   */
/*  FONT_DIR            The system directory where .AFM font files are kept  */
/*  EVEC_DIR            The system directory where .CEV files are kept       */
/*  DATA_DIR            The system directory where database files are kept   */
/*  LOCALE_DIR          The system directory where locale files are kept     */
/*  CHAR_IN             Determines assignment of input chars to lex classes  */
/*  CHAR_OUT            Determines appearance of literal chars in output     */
/*  DEBUG_ON            Non-zero means compile debug code (lout -d)          */
/*  ASSERT_ON           Non-zero means test assertions                       */
/*  LOCALE_ON           Non-zero means compile setlocale() etc. code         */
/*                                                                           */
/*  #define  INCL_DIR   "/usr/local/lib/lout/include"                        */
/*  #define  FONT_DIR   "/usr/local/lib/lout/font"                           */
/*  #define  EVEC_DIR   "/usr/local/lib/lout/evec"                           */
/*  #define  DATA_DIR   "/usr/local/lib/lout/data"                           */
/*  #define  HYPH_DIR   "/usr/local/lib/lout/hyph"                           */
/*  #define  LOCALE_DIR "/usr/local/lib/lout/locale"  only used if LOCALE_ON */
/*  #define  CHAR_IN    0                                                    */
/*  #define  CHAR_OUT   0                                                    */
/*  #define  DEBUG_ON   0                                                    */
/*  #define  ASSERT_ON  1                                                    */
/*  #define  LOCALE_ON  1                                                    */
/*                                                                           */
/*****************************************************************************/


/*@::File naming conventions and version@*************************************/
/*                                                                           */
/*  File naming conventions and version                                      */
/*                                                                           */
/*  LOUT_VERSION        Version information                                  */
/*  CROSS_DB            The default name of the cross reference database     */
/*  SOURCE_SUFFIX       Optional suffix of source files and include files    */
/*  INDEX_SUFFIX        The suffix of database index files                   */
/*  NEW_INDEX_SUFFIX    The suffix of new database index files               */
/*  DATA_SUFFIX         The suffix of database data files                    */
/*  NEW_DATA_SUFFIX     The additional suffix of new database data files     */
/*  HYPH_SUFFIX         The suffix of unpacked hyphenation files             */
/*  HYPH_PACKED_SUFFIX  The suffix of packed hyphenation files               */
/*  FILTER_IN           The prefix of the name of the input file to filters  */
/*  FILTER_OUT          The name of the output file to filters               */
/*  FILTER_ERR          The name of the error file to filters                */
/*                                                                           */
/*****************************************************************************/

#define	LOUT_VERSION	AsciiToFull("Basser Lout Version 3.02 (November 1994)")
#define	CROSS_DB	   AsciiToFull("lout")
#define	SOURCE_SUFFIX	   AsciiToFull(".lout")
#define	INDEX_SUFFIX	   AsciiToFull(".li")
#define	NEW_INDEX_SUFFIX   AsciiToFull(".lix")
#define	DATA_SUFFIX	   AsciiToFull(".ld")
#define	NEW_DATA_SUFFIX	   AsciiToFull("x")
#define	HYPH_SUFFIX	   AsciiToFull(".lh")
#define	HYPH_PACKED_SUFFIX AsciiToFull(".lp")
#define	FILTER_IN	   AsciiToFull("lout.in")
#define	FILTER_OUT	   AsciiToFull("lout.out")
#define	FILTER_ERR	   AsciiToFull("lout.err")

/*@::Significant limits@******************************************************/
/*                                                                           */
/*  Significant Limits (other insignificant ones appear in other files)      */
/*                                                                           */
/*  MAX_LEN             The maximum value storable in type LENGTH.           */
/*                                                                           */
/*  MAX_FILES           The maximum number of files.  This could only be     */
/*                      increased if the file_num() field of type FILE_POS   */
/*                      is enlarged beyond its present 16 bits.              */
/*                                                                           */
/*  MAX_LINE            1 + the maximum length of an input line in source    */
/*                      and database files.  This is used for the lexical    */
/*                      analyser's input line buffer only, and could be      */
/*                      increased immediately to 4096, and even further if   */
/*                      more than the current 12 bits was assigned to the    */
/*                      col_num() field of type FILE_POS.                    */
/*                                                                           */
/*  MAX_WORD            1 + the maximum length of a word storable in an      */
/*                      object record, which includes all file path names    */
/*                      too.  It is reasonable to make this MAX_LINE, since  */
/*                      a word longer than MAX_LINE cannot be read in.       */
/*                                                                           */
/*  MAX_OBJECT_REC      1 + the maximum size of an object record, measured   */
/*                      in ALIGNs.  The value chosen should exceed           */
/*                      ceiling( (wr + MAX_WORD - 4) / sizeof(ALIGN) )       */
/*                      where wr = sizeof(struct word_rec), so that words of */
/*                      length MAX_WORD-1 can be stored in an object record. */
/*                                                                           */
/*  MAX_BUFF            1 + the maximum length of a "standard buffer"; these */
/*                      buffers are used in a variety of places throughout   */
/*                      the program for holding one line of a font file,     */
/*                      one file path name, one symbol full name, etc.  This */
/*                      may be increased immediately without limit.          */
/*                                                                           */
/*  MAX_FONT            The maximum number of sized fonts allowed.  This     */
/*                      can be increased beyond 4096 only by setting aside   */
/*                      a larger word_font() field.                          */
/*                                                                           */
/*  MAX_COLOUR          The maximum number of distinct left parameters of    */
/*                      @SetColour and @SetColor symbols allowed (after      */
/*                      evaluation).  This can be increased beyond 4096      */
/*                      only by setting aside a larger word_colour() field.  */
/*                                                                           */
/*  MAX_LANGUAGE        The maximum number of distinct languages allowed.    */
/*                      This can be increased beyond 256 only by setting     */
/*                      aside a larger word_language() field.                */
/*                                                                           */
/*  MAX_LEX_STACK       The maximum depth of @Includes and @Databases.  This */
/*                      can be increased immediately by any small amount.    */
/*                                                                           */
/*****************************************************************************/

#define	MAX_LEN		32767
#define	MAX_FILES	65535
#define MAX_LINE        2048
#define MAX_WORD        2048
#define	MAX_OBJECT_REC	ceiling(sizeof(struct word_type)+MAX_WORD,sizeof(ALIGN))
#define MAX_BUFF        512
#define MAX_FONT	4096
#define MAX_COLOUR	4096
#define	MAX_LANGUAGE	256
#define	MAX_LEX_STACK	7

/*****************************************************************************/
/*                                                                           */
/*  Miscellaneous Macros                                                     */
/*                                                                           */
/*****************************************************************************/

#define	BOOLEAN		unsigned
#define	FALSE		0
#define	TRUE		1
#define	bool(x)		(x ? AsciiToFull("TRUE") : AsciiToFull("FALSE") )
#define	CHILD		0
#define	PARENT		1
#define	COL		0
#define	ROW		1
#define	dimen(x)	(x == COL ? AsciiToFull("COL") : AsciiToFull("ROW") )
#define	nil		( (OBJECT) NULL )
#define	null		( (FILE *) NULL )

#define max(a, b)	((a) < (b) ? (b) : (a))
#define min(a, b)	((a) < (b) ? (a) : (b))
#define	ceiling(a, b)	( ((a) - 1)/(b) + 1 )	/* ceiling(a/b)              */
#define is_odd(x)	( (x) & 1 )		/* TRUE if x is odd number   */

/*@::ALIGN, LENGTH, FONT_NUM, COLOUR_NUM, LANGUAGE_NUM, ENCODING, FULL_CHAR@**/
/*                                                                           */
/*  typedef ALIGN - used for forcing record alignment.                       */
/*                                                                           */
/*****************************************************************************/

typedef char *ALIGN;


/*****************************************************************************/
/*                                                                           */
/*  typedef LENGTH - an integer physical distance.                           */
/*                                                                           */
/*****************************************************************************/

typedef short int LENGTH;


/*****************************************************************************/
/*                                                                           */
/*  FONT_NUM - internal name for a font.                                     */
/*                                                                           */
/*****************************************************************************/

typedef unsigned FONT_NUM;


/*****************************************************************************/
/*                                                                           */
/*  COLOUR_NUM - internal name for a colour.                                 */
/*                                                                           */
/*****************************************************************************/

typedef unsigned COLOUR_NUM;


/*****************************************************************************/
/*                                                                           */
/*  LANGUAGE_NUM - internal name for a language.                             */
/*                                                                           */
/*****************************************************************************/

typedef unsigned LANGUAGE_NUM;


/*****************************************************************************/
/*                                                                           */
/*  ENCODING - internal name for a character encoding vector.                */
/*                                                                           */
/*****************************************************************************/

typedef unsigned char ENCODING;


/*****************************************************************************/
/*                                                                           */
/*  typedef FULL_CHAR - one of the characters manipulated by Lout.           */
/*                                                                           */
/*  This program does not deal with 7-bit ASCII characters.  Instead, its    */
/*  characters are defined by the FULL_CHAR typedef, and could be anything   */
/*  from 7-bit ASCII to 8-bit ISO-LATIN-1 to 16-bit UNICODE and beyond.      */
/*                                                                           */
/*  Unfortunately C favours signed 8-bit characters: literal strings are     */
/*  pointers to them, argv[] and the standard libraries assume them.  We get */
/*  around these problems by using our own library, including AsciiToFull()  */
/*  to convert an ASCII string (such as a C string) into a FULL_CHAR string. */
/*                                                                           */
/*  Formally this library appears in module z39.c; however since this        */
/*  implementation uses 8-bit unsigned characters, most of the routines      */
/*  can be implemented by macros containing type-cast calls to C standard    */
/*  library routines.  These appear in the z39.c externs list below.         */
/*                                                                           */
/*****************************************************************************/

typedef unsigned char FULL_CHAR;


/*@::Character literals@******************************************************/
/*                                                                           */
/*  Character Literals                                                       */
/*                                                                           */
/*  The following macros ensure that no Lout source is ever compared to a    */
/*  literal character other than '\0':                                       */
/*                                                                           */
/*****************************************************************************/

#define	CH_FLAG_OUTFILE		'o'	/* the -o command line flag          */
#define	CH_FLAG_SUPPRESS	's'	/* the -s command line flag          */
#define	CH_FLAG_NOKERN		'k'	/* the -k command line flag          */
#define	CH_FLAG_CROSS		'c'	/* the -c command line flag          */
#define	CH_FLAG_ERRFILE		'e'	/* the -e command line flag          */
#define	CH_FLAG_EPSFIRST	'E'	/* first letter of the -EPS flag     */
#define	CH_FLAG_DIRPATH		'D'	/* the -D command line flag          */
#define	CH_FLAG_ENCPATH		'C'	/* the -C command line flag          */
#define	CH_FLAG_FNTPATH		'F'	/* the -F command line flag          */
#define	CH_FLAG_HYPPATH		'H'	/* the -H command line flag          */
#define	CH_FLAG_INCPATH		'I'	/* the -I command line flag          */
#define	CH_FLAG_INCLUDE		'i'	/* the -i command line flag          */
#define	CH_FLAG_HYPHEN		'h'	/* the -h command line flag          */
#define	CH_FLAG_VERSION		'V'	/* the -V command line flag          */
#define	CH_FLAG_USAGE		'u'	/* the -u command line flag          */
#define	CH_FLAG_PLAIN		'p'	/* the -p command line flag          */
#define	CH_FLAG_FFPLAIN		'P'	/* the -P command line flag          */
#define	CH_FLAG_DEBUG		'd'	/* the -d command line flag          */
#define	CH_FLAG_INITALL		'x'	/* the -x command line flag          */

#define	CH_SPACE		' '	/* space character                   */
#define	CH_NEWLINE		'\n'	/* the newline character             */
#define	CH_SYMSTART		'@'	/* extra letter symbols may have     */
#define	CH_QUOTE		'"'	/* the quote character		     */
#define	CH_ZERO			'0'	/* the first digit character, zero   */
#define	CH_EIGHT		'8'	/* the last even digit character     */
#define	CH_NINE			'9'	/* the last odd digit character      */
#define	CH_INCGAP		'+'	/* begins an incrementing gap	     */
#define	CH_DECGAP		'-'	/* begins a decrementing gap	     */
#define	CH_MINUS		'-'	/* minus sign                        */
#define	CH_HYPHEN		'-'	/* the hyphen character		     */

#define	CH_UNIT_CM		'c'	/* unit of measurement: centimetres  */
#define	CH_UNIT_IN		'i'	/* unit of measurement: inches       */
#define	CH_UNIT_PT		'p'	/* unit of measurement: points       */
#define	CH_UNIT_EM		'm'	/* unit of measurement: ems          */
#define	CH_UNIT_FT		'f'	/* unit of measurement: fontsizes    */
#define	CH_UNIT_SP		's'	/* unit of measurement: spacewidths  */
#define	CH_UNIT_VS		'v'	/* unit of measurement: vspaces      */
#define	CH_UNIT_WD		'w'	/* unit of measurement: follwidths   */
#define	CH_UNIT_BD		'b'	/* unit of measurement: boundwidths  */
#define	CH_UNIT_RL		'r'	/* unit of measurement: relwidths    */
#define	CH_UNIT_DG		'd'	/* unit of measurement: degrees      */

#define	CH_MODE_EDGE		'e'	/* spacing mode: edge-to-edge        */
#define	CH_MODE_HYPH		'h'	/* spacing mode: hyphenation         */
#define	CH_MODE_MARK		'x'	/* spacing mode: mark-to-mark        */
#define	CH_MODE_OVER		'o'	/* spacing mode: overstrike          */
#define	CH_MODE_KERN		'k'	/* spacing mode: kerning             */
#define	CH_MODE_TABL		't'	/* spacing mode: tabulation          */

#define octaldigit(ch)		( (ch) >= '0' && (ch) <= '7' )
#define decimaldigit(ch)	( (ch) >= '0' && (ch) <= '9' )
#define	digitchartonum(ch)	( (ch) - '0' )
#define	numtodigitchar(ch)	( (ch) + '0' )
#define	beginsbreakstyle(ch)	( (ch) >= 'a' && (ch) <= 'z' )
#define	numericchar(ch)		( decimaldigit(ch) || (ch) == '.' )


/*@::String literals, FULL_CHAR type@*****************************************/
/*                                                                           */
/*  String Literals.                                                         */
/*                                                                           */
/*  All significant string literals are defined here.  The program has many  */
/*  others, however: format strings, debug output, etc.                      */
/*                                                                           */
/*****************************************************************************/

#define	STR_EMPTY		AsciiToFull("")
#define	STR_QUOTE		AsciiToFull("\"")
#define	STR_ESCAPE		AsciiToFull("\\")
#define	STR_COMMENT		AsciiToFull("#")
#define	STR_SPACE		AsciiToFull(" ")
#define	STR_FORMFEED		AsciiToFull("\f")
#define	STR_TAB			AsciiToFull("\t")
#define	STR_NEWLINE		AsciiToFull("\n")
#define	STR_LETTERS_LOWER	AsciiToFull("abcdefghijklmnopqrstuvwxyz")
#define	STR_LETTERS_UPPER	AsciiToFull("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
#define	STR_LETTERS_SYMSTART	AsciiToFull("@")

#if CHAR_IN==0
#define	STR_LETTERS_EXTRA0	AsciiToFull("")
#define	STR_LETTERS_EXTRA1	AsciiToFull("")
#define	STR_LETTERS_EXTRA2	AsciiToFull("")
#define	STR_LETTERS_EXTRA3	AsciiToFull("")
#define	STR_LETTERS_EXTRA4	AsciiToFull("")
#define	STR_LETTERS_EXTRA5	AsciiToFull("")
#define	STR_LETTERS_EXTRA6	AsciiToFull("")
#define	STR_LETTERS_EXTRA7	AsciiToFull("")
#else
#define	STR_LETTERS_EXTRA0	AsciiToFull("\300\301\302\303\304\305\306\307")
#define	STR_LETTERS_EXTRA1	AsciiToFull("\310\311\312\313\314\315\316\317")
#define	STR_LETTERS_EXTRA2	AsciiToFull("\320\321\322\323\324\325\326")
#define	STR_LETTERS_EXTRA3	AsciiToFull("\330\331\332\333\334\335\336\337")
#define	STR_LETTERS_EXTRA4	AsciiToFull("\340\341\342\343\344\345\346\347")
#define	STR_LETTERS_EXTRA5	AsciiToFull("\350\351\352\353\354\355\356\357")
#define	STR_LETTERS_EXTRA6	AsciiToFull("\360\361\362\363\364\365\366")
#define	STR_LETTERS_EXTRA7	AsciiToFull("\370\371\372\373\374\375\376\377")
#endif

#define	STR_STDIN		AsciiToFull("-")
#define	STR_STDOUT		AsciiToFull("-")
#define	STR_HYPHEN		AsciiToFull("-")
#define	STR_EPS			AsciiToFull("EPS")
#define	STR_ELSE		AsciiToFull("else")
#define	STR_NOCROSS		AsciiToFull("??")
#define	STR_BADKEY		AsciiToFull("badkey")
#define	STR_NONE		AsciiToFull("none")
#define	STR_ZERO		AsciiToFull("0")
#define	STR_PS_SPACENAME	AsciiToFull("space")
#define	STR_FONT_RECODE		AsciiToFull("Recode")
#define	STR_FONT_NORECODE	AsciiToFull("NoRecode")
#define	STR_COLOUR_NOCHANGE	AsciiToFull("nochange")

#define	STR_BREAK_HYPHEN	AsciiToFull("hyphen")
#define	STR_BREAK_NOHYPHEN	AsciiToFull("nohyphen")
#define	STR_BREAK_ADJUST	AsciiToFull("adjust")
#define	STR_BREAK_OUTDENT	AsciiToFull("outdent")
#define	STR_BREAK_RAGGED	AsciiToFull("ragged")
#define	STR_BREAK_CRAGGED	AsciiToFull("cragged")
#define	STR_BREAK_RRAGGED	AsciiToFull("rragged")
#define	STR_BREAK_LINES		AsciiToFull("lines")
#define	STR_BREAK_CLINES	AsciiToFull("clines")
#define	STR_BREAK_RLINES	AsciiToFull("rlines")

#define	STR_GAP_RJUSTIFY	AsciiToFull("1rt")
#define	STR_GAP_ZERO_HYPH	AsciiToFull("0ch")


/*@::GAP, STYLE@**************************************************************/
/*                                                                           */
/*  typedef GAP - what separates one object from another.                    */
/*                                                                           */
/*****************************************************************************/

typedef struct
{ unsigned char	ospare;			/* left for other things in STYLE    */
  BOOLEAN	omark	: 1;		/* TRUE if this gap is marked        */
  BOOLEAN	ojoin	: 1;		/* TRUE if joins exist across gap    */
  unsigned	ounits	: 3;		/* units of measurement: fixed, etc  */
  unsigned	omode	: 3;		/* spacing mode: edge-to-edge, etc   */
  LENGTH	owidth;			/* width of the gap                  */
} GAP;

#define	mark(x)		(x).omark
#define	join(x)		(x).ojoin
#define	units(x)	(x).ounits
#define	mode(x)		(x).omode
#define	width(x)	(x).owidth

#define SetGap(x, xmark, xjoin, xunits, xmode, xwidth)			\
( mark(x) = xmark, join(x) = xjoin, units(x) = xunits,			\
  mode(x) = xmode, width(x) = xwidth					\
)

#define GapCopy(x, y)							\
( mark(x) = mark(y), join(x) = join(y), units(x) = units(y),		\
  mode(x) = mode(y), width(x) = width(y)				\
)

#define ClearGap(x)	SetGap(x, FALSE, TRUE, FIXED_UNIT, NO_MODE, 0)


/*****************************************************************************/
/*                                                                           */
/*  typedef STYLE - information about how to break text, etc.                */
/*                                                                           */
/*****************************************************************************/

typedef struct
{ GAP		oline_gap;		/* separation between lines          */
  union {
    GAP		ospace_gap;		/* separation indiced by white space */
    struct {
      unsigned	ohyph_style    : 2;	/* hyphenation off or on             */
      unsigned	ofill_style    : 2;	/* fill lines with text off/on       */
      unsigned	odisplay_style : 3;	/* display lines adjusted, ragged... */
    } oss;
  } osu;
  FONT_NUM	ofont      : 12;	/* current font                      */
  COLOUR_NUM	ocolour    : 12;	/* current colour		     */
  LANGUAGE_NUM	olanguage  : 7;		/* current language		     */
} STYLE;

#define	line_gap(x)	(x).oline_gap
#define	space_gap(x)	(x).osu.ospace_gap
#define	hyph_style(x)	(x).osu.oss.ohyph_style
#define	fill_style(x)	(x).osu.oss.ofill_style
#define	display_style(x)(x).osu.oss.odisplay_style
#define	font(x)		(x).ofont
#define	colour(x)	(x).ocolour
#define	language(x)	(x).olanguage

#define StyleCopy(x, y)							\
( GapCopy(line_gap(x), line_gap(y)),					\
  hyph_style(x) = hyph_style(y),					\
  fill_style(x) = fill_style(y),					\
  display_style(x) = display_style(y),					\
  GapCopy(space_gap(x), space_gap(y)),					\
  font(x) = font(y),							\
  colour(x) = colour(y),						\
  language(x) = language(y)						\
)


/*@::CONSTRAINT, FILE_NUM, FILE_POS, LIST@************************************/
/*                                                                           */
/*  typedef CONSTRAINT - a size constraint.                                  */
/*                                                                           */
/*****************************************************************************/

typedef struct
{ LENGTH  obc;
  LENGTH  obfc;
  LENGTH  ofc;
  LENGTH  osparec;
} CONSTRAINT;

#define	bc(x)		(x).obc
#define	bfc(x)		(x).obfc
#define	fc(x)		(x).ofc
#define	sparec(x)	(x).osparec
#define	constrained(x)	(bc(x)!=MAX_LEN || bfc(x)!=MAX_LEN || fc(x)!=MAX_LEN)

#define	SetConstraint(c,x,y,z)	(bc(c) = (x),   bfc(c) = (y),    fc(c) = (z))
#define	CopyConstraint(x, y)	(bc(x) = bc(y), bfc(x) = bfc(y), fc(x) = fc(y))
#define FitsConstraint(b, f, c)	(b <= bc(c)  && b + f <= bfc(c) && f <= fc(c))

#define	ig_fnum(x)	bc(constraint(x))
#define	ig_xtrans(x)	bfc(constraint(x))
#define	ig_ytrans(x)	fc(constraint(x))


/*****************************************************************************/
/*                                                                           */
/*  typedef FILE_NUM - the internal representation of a file.                */
/*                                                                           */
/*****************************************************************************/

typedef unsigned short	FILE_NUM;
#define	NO_FILE		0


/*****************************************************************************/
/*                                                                           */
/*  typedef FILE_POS - a position in the set of input files.                 */
/*                                                                           */
/*****************************************************************************/

typedef	struct
{ unsigned char	 otype;			/* space for object type field	     */
  unsigned char	 orec_size;		/* space for object record size      */
  FILE_NUM	 ofile_num;		/* no. of file this record is from   */
  unsigned       oline_num  : 20;	/* the line number of this record    */
  unsigned       ocol_num   : 12;	/* column number this is related to  */
} FILE_POS;

#define	file_num(x)	(x).ofile_num
#define	col_num(x)	(x).ocol_num
#define	line_num(x)	(x).oline_num

#define FposCopy(x, y)							\
( file_num(x) = file_num(y),						\
  line_num(x) = line_num(y),						\
  col_num(x)  = col_num(y)						\
)


/*****************************************************************************/
/*                                                                           */
/*  typedef LIST - two pointers used to make one doubly linked list          */
/*                                                                           */
/*****************************************************************************/

typedef struct { union rec *opred, *osucc; } LIST;


/*@::FIRST_UNION@*************************************************************/
/*                                                                           */
/*  typedef FIRST_UNION - first eight bytes of object record (after LISTs).  */
/*                                                                           */
/*  The fpos is overwritten in WORDs and QWORDs during FixAndPrintObject by  */
/*  the horizontal coordinate of the word, which has to be remembered.       */
/*                                                                           */
/*****************************************************************************/

typedef union
{
  FILE_POS	ofpos;
  struct
  {	unsigned char	otype, orec_size;
	int		oword_save_mark;
  } os11;

} FIRST_UNION;


/*@::SECOND_UNION, THIRD_UNION, FOURTH_UNION@*********************************/
/*                                                                           */
/*  typedef SECOND_UNION - four bytes holding various flags etc.             */
/*                                                                           */
/*****************************************************************************/

typedef union
{
  struct /* used by all tokens */
  {	unsigned char	oprecedence;
	unsigned char	ohspace, ovspace;
  } os21;

  struct /* used by WORD objects only */
  {	FONT_NUM	oword_font     : 12;
	COLOUR_NUM	oword_colour   : 12;
	LANGUAGE_NUM	oword_language : 7;
	unsigned	oword_hyph     : 1;
  } os22;

  struct /* used by non-WORD objects */
  {	BOOLEAN		onon_blocking: 1;
	BOOLEAN		osized       : 1;
	BOOLEAN		othreaded    : 1;
	BOOLEAN		oexternal    : 1;
	BOOLEAN		oblocked     : 1;
	BOOLEAN		obackward    : 1;
	BOOLEAN		otrigger_ext : 1;
	BOOLEAN	        omust_expand : 1;
	unsigned char	ocross_type;	     /* CROSS objects only */
  } os23;

  struct /* used by WORD and QWORD when they are database nodes */
  {	unsigned short	oleft_pos;
	unsigned short	oreading;
  } os24;

  struct /* used by WORD and QWORD when they are font records */
  {	FONT_NUM	ofont_num : 12;
	unsigned short	ofont_page;
  } os25;

  struct /* used by symbol table entries */
  {	unsigned char	oprecedence;
	BOOLEAN		ois_tag		     : 1;
	BOOLEAN		ohas_tag             : 1;
	BOOLEAN		ohas_lpar            : 1;
	BOOLEAN		ohas_rpar            : 1;
	BOOLEAN		oright_assoc         : 1;
	BOOLEAN		ois_target           : 1;
	BOOLEAN		ohas_target          : 1;
	BOOLEAN		oforce_target	     : 1;
	BOOLEAN		ohas_body            : 1;
	BOOLEAN		oindefinite          : 1;
	BOOLEAN		orecursive           : 1;
	BOOLEAN		ouses_extern_target  : 1;
	BOOLEAN		ois_extern_target    : 1;
	BOOLEAN		ois_key		     : 1;
	BOOLEAN		ohas_key	     : 1;
	BOOLEAN		odirty               : 1;
	BOOLEAN		ovisible	     : 1;
	BOOLEAN		ohas_mark	     : 1;
	BOOLEAN		ohas_join	     : 1;
	BOOLEAN		ohas_par             : 1;
	BOOLEAN		ouses_galley	     : 1;
  } os26;

} SECOND_UNION;


/*****************************************************************************/
/*                                                                           */
/*  typedef THIRD_UNION - eight bytes usually holding an object size.        */
/*                                                                           */
/*  In database records this space is used for a file pointer; in certain    */
/*  WORD objects used privately in z10.c it is used for a galley-position.   */
/*  In font records it holds the font size, space width, etc.  In filter     */
/*  words it holds a pointer to the symbol being filtered.                   */
/*                                                                           */
/*****************************************************************************/

typedef union
{
  struct
  {	LENGTH	oback[2];
	LENGTH	ofwd[2];
  } os31;

  FILE *ofilep;

  struct
  {	LENGTH	ofont_size;
	LENGTH	ofont_xheight2;
	LENGTH	ofont_spacewidth;
	ENCODING ofont_encoding;
	BOOLEAN	ofont_recoded:  1;
	BOOLEAN	ofont_firstpage:  1;
  } os32;

  struct
  {	BOOLEAN ogall_rec;
	int	ogall_pos;
  } os33;

  union rec *ofilter_actual;

} THIRD_UNION;


/*****************************************************************************/
/*                                                                           */
/*  typedef FOURTH_UNION - twelve bytes holding a STYLE or CONSTRAINT.       */
/*                                                                           */
/*****************************************************************************/

typedef union
{
  STYLE		osave_style;
  CONSTRAINT	oconstraint;

} FOURTH_UNION;


/*@::OBJECT@******************************************************************/
/*                                                                           */
/*  typedef OBJECT - the general-purpose record used throughout Lout.        */
/*                                                                           */
/*****************************************************************************/

typedef union rec
{
  struct word_type	/* all fields of WORD and QWORD, token and object */
  {  LIST		olist[2];
     FIRST_UNION	ou1;
     SECOND_UNION	ou2;
     THIRD_UNION	ou3;
     FULL_CHAR		ostring[4];
  } os1;

  struct closure_type	/* all fields of CLOSURE, both as token and object */
  {  LIST		olist[2];
     FIRST_UNION	ou1;
     SECOND_UNION	ou2;
     THIRD_UNION	ou3;
     FOURTH_UNION	ou4;
     union rec		*oactual;
     union
     { union rec *owhereto;
       LENGTH    osave_mark;
     } oux;
     union rec *oready_galls;
  } os2;
  
  struct object_type	/* the general OBJECT */
  {  LIST		olist[2];
     FIRST_UNION	ou1;
     SECOND_UNION	ou2;
     THIRD_UNION	ou3;
     FOURTH_UNION	ou4;
  } os3;

  struct link_type	/* LINK */
  {  LIST		olist[2];
     unsigned char	otype;
     unsigned char	onumber;
     unsigned char	odb_targ;
  } os4;
  
  struct gapobj_type	/* GAP_OBJ */
  {  LIST		olist[2];
     FIRST_UNION	ou1;
     SECOND_UNION	ou2;
     GAP		ogap;
     int		osave_badness;		/* optimum paragraph breaker */
     LENGTH		osave_space;		/* optimum paragraph breaker */
     LENGTH		osave_actual_gap;	/* optimum paragraph breaker */
     union rec  	*osave_prev;		/* optimum paragraph breaker */
  } os5;

  struct symbol_type
  {  LIST		olist[2];
     FIRST_UNION	ou1;
     SECOND_UNION	ou2;
     union rec		*oenclosing;
     union rec		*osym_body;
     union rec		*obase_uses;
     union rec		*ouses;
     union rec		*omarker;
     union rec		*ocross_sym;
     union rec		*oimports;
     union rec		*ofilter;
     union rec		*ouse_invocation;
     short unsigned 	opredefined;
     unsigned char	ouses_count;
  } os6;

  struct cr_type
  {  LIST		olist[2];
     unsigned char	otype;
     unsigned char	otarget_state;
     FILE_NUM		otarget_file;
     FILE_NUM		ocr_file;
     union rec		*otarget_val;
     int		otarget_seq;
     int		otarget_pos;
     int		ocr_seq;
     int		ogall_seq;
     union rec		*osymb;
     union rec		*ogall_tag;
     FILE_NUM		ogall_tfile;
  } os7;

  struct ext_gall_type
  {  LIST		olist[2];
     unsigned char	otype;
     FILE_NUM		oeg_fnum;
     long		oeg_fpos;
     long		oeg_cont;
     union rec		*oeg_symbol;
  } os8;

  struct uses_type
  {  union rec	*oitem;
     union rec	*onext;
  } os9;

  struct hash_entry_type
  {  LIST	olist[1];
  } os10;

} *OBJECT;


/*@::macros for fields of OBJECT@*********************************************/
/*                                                                           */
/*  Macros for fields of OBJECT.                                             */
/*                                                                           */
/*****************************************************************************/

#define	succ(x, dim)		(x)->os1.olist[dim].osucc
#define	pred(x, dim)		(x)->os1.olist[dim].opred

#define type(x)			(x)->os1.ou1.os11.otype
#define	rec_size(x)		(x)->os1.ou1.os11.orec_size
#define	precedence(x)		(x)->os1.ou2.os21.oprecedence
#define	hspace(x)		(x)->os1.ou2.os21.ohspace
#define	vspace(x)		(x)->os1.ou2.os21.ovspace

#define	word_font(x)		(x)->os1.ou2.os22.oword_font
#define	word_colour(x)		(x)->os1.ou2.os22.oword_colour
#define	word_language(x)	(x)->os1.ou2.os22.oword_language
#define	word_hyph(x)		(x)->os1.ou2.os22.oword_hyph
#define	filter_use_begin(x)	(x)->os1.ou2.os22.oword_colour

#define	non_blocking(x)		(x)->os1.ou2.os23.onon_blocking
#define	vert_sized(x)		non_blocking(x)
#define	sized(x)		(x)->os1.ou2.os23.osized
#define	threaded(x)		(x)->os1.ou2.os23.othreaded
#define	external(x)		(x)->os1.ou2.os23.oexternal
#define	blocked(x)		(x)->os1.ou2.os23.oblocked
#define	seen_nojoin(x)		blocked(x)
#define	backward(x)		(x)->os1.ou2.os23.obackward
#define	trigger_externs(x)	(x)->os1.ou2.os23.otrigger_ext
#define	must_expand(x)		(x)->os1.ou2.os23.omust_expand
#define	cross_type(x)		(x)->os1.ou2.os23.ocross_type
#define	thr_state(x)		cross_type(x)

#define	left_pos(x)		(x)->os1.ou2.os24.oleft_pos
#define	reading(x)		(x)->os1.ou2.os24.oreading

#define	is_tag(x)		(x)->os1.ou2.os26.ois_tag
#define	has_tag(x)		(x)->os1.ou2.os26.ohas_tag
#define	has_lpar(x)		(x)->os1.ou2.os26.ohas_lpar
#define	has_rpar(x)		(x)->os1.ou2.os26.ohas_rpar
#define	right_assoc(x)		(x)->os1.ou2.os26.oright_assoc
#define	is_target(x)		(x)->os1.ou2.os26.ois_target
#define	has_target(x)		(x)->os1.ou2.os26.ohas_target
#define	force_target(x)		(x)->os1.ou2.os26.oforce_target
#define	has_body(x)		(x)->os1.ou2.os26.ohas_body
#define	indefinite(x)		(x)->os1.ou2.os26.oindefinite
#define	recursive(x)		(x)->os1.ou2.os26.orecursive
#define	uses_extern_target(x)	(x)->os1.ou2.os26.ouses_extern_target
#define	is_extern_target(x)	(x)->os1.ou2.os26.ois_extern_target
#define	is_key(x)		(x)->os1.ou2.os26.ois_key
#define	has_key(x)		(x)->os1.ou2.os26.ohas_key
#define	dirty(x)		(x)->os1.ou2.os26.odirty
#define	visible(x)		(x)->os1.ou2.os26.ovisible
#define	has_mark(x)		(x)->os1.ou2.os26.ohas_mark
#define	has_join(x)		(x)->os1.ou2.os26.ohas_join
#define	has_par(x)		(x)->os1.ou2.os26.ohas_par
#define	uses_galley(x)		(x)->os1.ou2.os26.ouses_galley

#define	fpos(x)			(x)->os1.ou1.ofpos
#define word_save_mark(x)	(x)->os1.ou1.os11.oword_save_mark

#define	back(x, dim)		(x)->os1.ou3.os31.oback[dim]
#define	fwd(x, dim)		(x)->os1.ou3.os31.ofwd[dim]
#define	size(x, dim)		(back(x, dim) + fwd(x, dim))
#define	filep(x)		(x)->os1.ou3.ofilep
#define	filter_actual(x)	(x)->os1.ou3.ofilter_actual
#define	db_checksym(x)		filter_actual(x)

#define	gall_rec(x)		(x)->os1.ou3.os33.ogall_rec
#define	gall_pos(x)		(x)->os1.ou3.os33.ogall_pos

#define string(x)		(x)->os1.ostring

#define	save_style(x)		(x)->os2.ou4.osave_style
#define	constraint(x)		(x)->os2.ou4.oconstraint
#define	shift_type(x)		width(space_gap(save_style(x)))
#define	shift_gap(x)		line_gap(save_style(x))

#define actual(x)		(x)->os2.oactual
#define whereto(x)		(x)->os2.oux.owhereto
#define save_mark(x)		(x)->os2.oux.osave_mark
#define ready_galls(x)		(x)->os2.oready_galls

#define	number(x)		(x)->os4.onumber
#define	db_targ(x)		(x)->os4.odb_targ

#define	gap(x)			(x)->os5.ogap
#define	save_badness(x)		(x)->os5.osave_badness
#define	save_space(x)		(x)->os5.osave_space
#define	save_actual_gap(x)	(x)->os5.osave_actual_gap
#define	save_prev(x)		(x)->os5.osave_prev

#define	enclosing(x)		(x)->os6.oenclosing
#define	sym_body(x)		(x)->os6.osym_body
#define	base_uses(x)		(x)->os6.obase_uses
#define	uses(x)			(x)->os6.ouses
#define	marker(x)		(x)->os6.omarker
#define	cross_sym(x)		(x)->os6.ocross_sym
#define	imports(x)		(x)->os6.oimports
#define	filter(x)		(x)->os6.ofilter
#define	use_invocation(x)	(x)->os6.ouse_invocation
#define	predefined(x)		(x)->os6.opredefined
#define	uses_count(x)		(x)->os6.ouses_count

#define	target_state(x)		(x)->os7.otarget_state
#define	target_file(x)		(x)->os7.otarget_file
#define	cr_file(x)		(x)->os7.ocr_file
#define	target_val(x)		(x)->os7.otarget_val
#define	target_seq(x)		(x)->os7.otarget_seq
#define	target_pos(x)		(x)->os7.otarget_pos
#define	cr_seq(x)		(x)->os7.ocr_seq
#define	gall_seq(x)		(x)->os7.ogall_seq
#define	symb(x)			(x)->os7.osymb
#define	gall_tag(x)		(x)->os7.ogall_tag
#define	gall_tfile(x)		(x)->os7.ogall_tfile

#define	eg_fnum(x)		(x)->os8.oeg_fnum
#define	eg_fpos(x)		(x)->os8.oeg_fpos
#define	eg_cont(x)		(x)->os8.oeg_cont
#define	eg_symbol(x)		(x)->os8.oeg_symbol

#define	item(x)			(x)->os9.oitem
#define	next(x)			(x)->os9.onext

#define	font_num(x)		(x)->os1.ou2.os25.ofont_num
#define	font_page(x)		(x)->os1.ou2.os25.ofont_page
#define	font_size(x)		(x)->os1.ou3.os32.ofont_size
#define	font_xheight2(x)	(x)->os1.ou3.os32.ofont_xheight2
#define	font_spacewidth(x)	(x)->os1.ou3.os32.ofont_spacewidth
#define	font_encoding(x)	(x)->os1.ou3.os32.ofont_encoding
#define	font_recoded(x)		(x)->os1.ou3.os32.ofont_recoded
#define	font_firstpage(x)	(x)->os1.ou3.os32.ofont_firstpage


/*@::FONT_INFO@***************************************************************/
/*                                                                           */
/*  typedef FONT_INFO - information about font metrics etc.  Really private  */
/*  but shared between z37.c and z24.c                                       */
/*                                                                           */
/*****************************************************************************/

struct metrics {
  LENGTH up;
  LENGTH down;
  LENGTH left;
  LENGTH right;
};

typedef struct font_rec {
  struct metrics	*size_table;		/* metrics of sized fonts    */
  FULL_CHAR		*lig_table;		/* ligatures                 */
  OBJECT		font_table;		/* record of sized fonts     */
  OBJECT		original_font;		/* font rec before resizing  */
  unsigned short	*kern_table;		/* first kerning chars       */
  FULL_CHAR		*kern_chars;		/* second kerning chars      */
  unsigned char		*kern_value;		/* points into kern_lengths  */
  LENGTH		*kern_sizes;		/* sizes of kernings         */
} FONT_INFO;


/*@::object types@************************************************************/
/*                                                                           */
/*  OBJECT, TOKEN AND OTHER TYPES inhabiting type(x) and predefined(x)       */
/*                                                                           */
/*  Key letters in the adjacent comment indicate where the tag is legal:     */
/*                                                                           */
/*    t  a token type, pushed on token stack                                 */
/*    o  an object type (returned by reduce(), inserted by Manifest)         */
/*    i  an index type (a child of a galley header other than an object)     */
/*    s  a predefined symbol (some symbol table entry has this predefined()) */
/*    n  an indefinite object i.e. one which is ignored in catenation ops    */
/*                                                                           */
/*****************************************************************************/

#define	LINK		 0		/*        a link between objects     */
#define	GAP_OBJ		 1		/*  o     a gap object               */
#define	CLOSURE		 2		/* to  n  a closure of a symbol      */
#define	NULL_CLOS	 3		/* to sn  @Null                      */
#define	CROSS		 4		/* to sn  && (a cross reference obj) */
#define	HEAD		 5		/*  o  n  a galley header            */
#define	SPLIT		 6		/*  o     @Split                     */
#define	PAR		 7		/*  o     a parameter of a closure   */
#define	WORD		 8		/*  o     a word                     */
#define	QWORD		 9		/*  o     a word (was quoted in i/p) */
#define	ROW_THR		10		/*  o     a row thread               */
#define	COL_THR		11		/*  o     a column thread            */
#define	ACAT		12		/* to s   a sequence of &-ed objs    */
#define	HCAT		13		/* to s   a sequence of |-ed objs    */
#define	VCAT		14		/* to s   a sequence of /-ed objs    */
#define	ONE_COL		15		/* to s   @OneCol                    */
#define	ONE_ROW		16		/* to s   @OneRow                    */
#define	WIDE		17		/* to s   @Wide                      */
#define	HIGH		18		/* to s   @High                      */
#define	HSHIFT		19		/* to s   @HShift                    */
#define	VSHIFT		20		/* to s   @VShift                    */
#define	HSCALE		21		/* to s   @HScale                    */
#define	VSCALE		22		/* to s   @HScale                    */
#define	SCALE		23		/* to s   @Scale                     */
#define	HCONTRACT	24		/* to s   @HContract                 */
#define	VCONTRACT	25		/* to s   @VContract                 */
#define	HEXPAND		26		/* to s   @HExpand                   */
#define	VEXPAND		27		/* to s   @VExpand                   */
#define	PADJUST		28		/* to s   @PAdjust                   */
#define	HADJUST		29		/* to s   @HAdjust                   */
#define	VADJUST		30		/* to s   @VAdjust                   */
#define	ROTATE		31		/* to s   @Rotate                    */
#define	CASE		32		/* to s   @Case                      */
#define	YIELD		33		/* to s   @Yield                     */
#define	BACKEND		34		/* to s   @BackEnd                   */
#define	FILTERED	35		/* to s   filtered object (no name)  */
#define	XCHAR		36		/* to s   @Char                      */
#define	FONT		37		/* to s   @Font                      */
#define	SPACE		38		/* to s   @Space                     */
#define	BREAK		39		/* to s   @Break                     */
#define	COLOUR		40		/* to s   @SetColour and @SetColor   */
#define	LANGUAGE	41		/* to s   @Language                  */
#define	CURR_LANG	42		/* to s   @CurrLang                  */
#define	NEXT		43		/* to s   @Next                      */
#define	ENV		44		/* to s   @LEnv                      */
#define	CLOS		45		/* to s   @LClos                     */
#define	LVIS		46		/* to s   @LVis                      */
#define	LUSE		47		/* to s   @LVis                      */
#define	OPEN		48		/* to s   @Open                      */
#define	TAGGED		49		/* to s   @Tagged                    */
#define	INCGRAPHIC	50		/* to s   @IncludeGraphic            */
#define	SINCGRAPHIC	51		/* to s   @SysIncludeGraphic         */
#define	GRAPHIC		52		/* to s   @Graphic                   */

#define	TSPACE		53		/* t      a space token, parser only */
#define	TJUXTA		54		/* t      a juxta token, parser only */
#define	LBR		55		/* t  s   left brace token           */
#define	RBR		56		/* t  s   right brace token          */
#define	BEGIN		57		/* t  s   @Begin token               */
#define	END		58		/* t  s   @End token                 */
#define	USE		59		/* t  s   @Use                       */
#define	GSTUB_NONE	60		/* t      a galley stub, no rpar     */
#define	GSTUB_INT	61		/* t      galley stub internal rpar  */
#define	GSTUB_EXT	62		/* t      galley stub external rpar  */
#define	UNEXPECTED_EOF	63		/* t      unexpected end of file     */
#define	INCLUDE		64		/*    s   @Include                   */
#define	SYS_INCLUDE	65		/*    s   @SysInclude                */
#define	PREPEND		66		/*    s   @Prepend                   */
#define	SYS_PREPEND	67		/*    s   @SysPrepend                */
#define	DATABASE	68		/*    s   @Database                  */
#define	SYS_DATABASE	69		/*    s   @SysDatabase               */
#define	START		70		/*    s   \Start                     */

#define	DEAD		71		/*   i    a dead galley              */
#define	UNATTACHED	72		/*   i    an inner, unsized galley   */
#define	RECEPTIVE	73		/*   i    a receptive object index   */
#define	RECEIVING	74		/*   i    a receiving object index   */
#define	RECURSIVE	75		/*   i    a recursive definite obj.  */
#define	PRECEDES	76		/*   i    an ordering constraint     */
#define	FOLLOWS		77		/*   i    other end of ordering c.   */
#define	CROSS_FOLL	78		/*   i    following type cross-ref   */
#define	GALL_FOLL	79		/*   i    galley with &&following    */
#define	CROSS_TARG	80		/*   i    value of cross-ref         */
#define	GALL_TARG	81		/*   i    target of these galleys    */
#define	GALL_PREC	82		/*   i    galley with &&preceding    */
#define	CROSS_PREC	83		/*   i    preceding type cross-ref   */
#define	SCALE_IND	84		/*   i    index of auto SCALE        */
#define	EXPAND_IND	85		/*   i    index of HEXPAND or VEXPD  */
#define	THREAD		86		/*        a sequence of threads      */
#define	CROSS_SYM	87		/*        cross-ref info             */
#define	CR_ROOT		88		/*        RootCross                  */
#define	MACRO		89		/*        a macro symbol             */
#define	LOCAL		90		/*        a local symbol             */
#define	LPAR		91		/*        a left parameter           */
#define	NPAR		92		/*        a named parameter          */
#define	RPAR		93		/*        a right parameter          */
#define	EXT_GALL	94		/*        an external galley         */
#define	CR_LIST		95		/*        a list of cross references */
#define	DISPOSED	96		/*        a disposed record          */

#define is_indefinite(x)  ((x) >= CLOSURE && (x) <= HEAD)
#define is_definite(x) 	 ((x) >= SPLIT && (x) <= GRAPHIC)
#define	is_par(x)	((x) >= LPAR   && (x) <= RPAR)
#define	is_index(x)	((x) >= DEAD && (x) <= EXPAND_IND)
#define	is_type(x)	((x) >= LINK && (x) < DISPOSED)
#define	is_word(x)	((x) == WORD || (x) == QWORD)
#define is_cat_op(x)    (((x)>=ACAT && (x)<=VCAT) || (x)==TSPACE || (x)<=TJUXTA)


/*@::miscellaneous constants@*************************************************/
/*                                                                           */
/*  Miscellaneous globally defined constants                                 */
/*                                                                           */
/*****************************************************************************/

/* gap modes occupying mode(x) */
#define	NO_MODE		0		/* for error detection: no mode      */
#define	EDGE_MODE	1		/* edge-to-edge spacing              */
#define	HYPH_MODE	2		/* edge-to-edge with hyphenation     */
#define	MARK_MODE	3		/* mark-to-mark spacing              */
#define	OVER_MODE	4		/* overstrike spacing                */
#define	KERN_MODE	5		/* kerning spacing                   */
#define	TAB_MODE	6		/* tabulation spacing                */
#define	ADD_HYPH	7		/* temp value used by FillObject     */

/* hyph_style(style) options                                                 */
#define	HYPH_UNDEF	0		/* hyphenation option undefined      */
#define	HYPH_OFF	1		/* hyphenation off                   */
#define	HYPH_ON		2		/* hyphenation on                    */

/* fill_style(style) options                                                 */
#define	FILL_UNDEF	0		/* fill option undefined             */
#define	FILL_OFF	1		/* no filling of lines               */
#define	FILL_ON		2		/* fill lines with text              */

/* display_style(style) options                                              */
#define	DISPLAY_UNDEF	0		/* display option undefined          */
#define	DISPLAY_ADJUST	1		/* adjust lines (except last)        */
#define	DISPLAY_OUTDENT	2		/* outdent lines (except first)      */
#define	DISPLAY_LEFT	3		/* left-justify lines, no adjust     */
#define	DISPLAY_CENTRE	4		/* centre lines, no adjust           */
#define	DISPLAY_RIGHT	5		/* right-justify lines, no adjust    */
#define	DO_ADJUST	6		/* placed in ACATs when adjust need  */

/* sides of a mark */
#define	BACK		97		/* means lies to left of mark        */
#define	ON		98		/* means lies on mark                */
#define	FWD		99		/* means lies to right of mark       */

/* statuses of thread objects */
#define	NOTSIZED	 0		/* this thread object is not sized   */
#define	SIZED		 1		/* thread is sized but not printed   */
#define	FINALSIZE	 2		/* thread object size is now final   */

/* constraint statuses */
#define	PROMOTE	       100		/* this component may be promoted    */
#define	CLOSE	       101		/* must close dest before promoting  */
#define	BLOCK	       102		/* cannot promote this component     */
#define	CLEAR	       103		/* this constraint is now satisfied  */

/* gap increment types */
#define	GAP_ABS	       104		/* absolute,  e.g.  3p               */
#define	GAP_INC	       105		/* increment, e.g. +3p               */
#define	GAP_DEC	       106		/* decrement, e.g. -3p               */

/* file types */
#define	SOURCE_FILE	 0		/* input file from command line      */
#define	INCLUDE_FILE	 1		/* @Include file                     */
#define	INCGRAPHIC_FILE	 2		/* @IncludeGraphic file              */
#define	DATABASE_FILE	 3		/* database file                     */
#define	INDEX_FILE	 4		/* database index file               */
#define	FONT_FILE	 5		/* font file                         */
#define	PREPEND_FILE	 6		/* PostScript prologue file          */
#define	HYPH_FILE	 7		/* hyphenation file                  */
#define	HYPH_PACKED_FILE 8		/* packed hyphenation file           */
#define	ENCODING_FILE	 9		/* encoding vector file              */
#define	FILTER_FILE	10		/* filter output file                */

/* path types (i.e. sequences of directories for file searching) */
#define	SOURCE_PATH	 0		/* path to search for source files   */
#define	INCLUDE_PATH	 1		/* path for @Include files           */
#define	SYSINCLUDE_PATH	 2		/* path for @SysInclude files        */
#define	DATABASE_PATH	 3		/* path for @Database files          */
#define	SYSDATABASE_PATH 4		/* path for @SysDatabase files       */
#define	FONT_PATH	 5		/* path for font metrics (AFM) files */
#define	HYPH_PATH	 6		/* path for hyphenation files        */
#define	ENCODING_PATH	 7		/* path for encoding (CEV) files     */

/* units of measurement */
#define	NO_UNIT		 0		/* no unit - for error detection     */
#define	FIXED_UNIT	 1		/* inches, cm, points, ems           */
#define	FRAME_UNIT	 2		/* b unit (frame widths)             */
#define	AVAIL_UNIT	 3		/* r unit (available spaces)         */
#define	DEG_UNIT	 4		/* d unit (degrees)                  */
#define	NEXT_UNIT	 5		/* w unit (inners)                   */
 
/* units of distance as multiples of the basic unit */
#define	CM	       567		/* 1 centimetre                      */
#define	IN	      1440		/* 1 inch                            */
#define	EM	       120		/* 1 em (= 1/12 inch)                */
#define	PT		20		/* 1 point (= 1/72 inch)             */
#define	FR	      4096		/* virtual unit for frame units      */
#define	DG	       128		/* virtual unit for degrees          */
#define	SF	       128		/* virtual unit for @Scale factors   */

/* default size of characters for the PLAINTEXT back end */
#define	PLAIN_WIDTH    144		/* default char width, 10 per inch   */
#define	PLAIN_HEIGHT   240		/* default char height, 6 per inch   */

/* precedences */
#define	NO_PREC		 0		/* lower than any precedence         */
#define	BEGIN_PREC	 1		/* precedence of @Begin              */
#define	END_PREC	 2		/* precedence of @End                */
#define	LBR_PREC	 3		/* precedence of {                   */
#define	RBR_PREC	 4		/* precedence of }                   */
#define	VCAT_PREC	 5		/* precedence of /                   */
#define	HCAT_PREC	 6		/* precedence of |                   */
#define	ACAT_PREC	 7		/* precedence of & and white space   */
#define	MIN_PREC        10		/* minimum precedence of user ops    */
#define	MAX_PREC       100		/* maximim precedence of user ops    */
#define	DEFAULT_PREC   100		/* default precedence of user ops    */
#define CROSSOP_PREC   101		/* precedence of cross op &&         */
#define GAP_PREC       102		/* precedence of gap op after cat op */
#define JUXTA_PREC     103		/* precedence of juxtaposition &     */
#define	FORCE_PREC     104		/* higher than any precedence        */

/* back ends */
#define POSTSCRIPT       0		/* PostScript back end               */
#define	PLAINTEXT	 1		/* plain text back end               */

/* error types */
#define	INTERN	0			/* internal error (i.e. bug)         */
#define	FATAL	1			/* fatal error, abort now            */
#define	WARN	2			/* warning, non-fatal                */

/* status values returned by AttachGalley() */
#define	ATTACH_KILLED	 0
#define	ATTACH_INPUT	 1
#define	ATTACH_NOTARGET	 2
#define	ATTACH_SUSPEND	 3
#define	ATTACH_NULL	 4
#define	ATTACH_ACCEPT	 5

/*@::Keywords@****************************************************************/
/*                                                                           */
/*  Keywords.                                                                */
/*                                                                           */
/*****************************************************************************/

#define	KW_START		AsciiToFull("\\Start")
#define	KW_PRINT		AsciiToFull("\\Print")
#define	KW_DEF			AsciiToFull("def")
#define	KW_FONTDEF		AsciiToFull("fontdef")
#define	KW_LANGDEF		AsciiToFull("langdef")
#define	KW_FORCE		AsciiToFull("force")
#define	KW_INTO			AsciiToFull("into")
#define	KW_EXTEND		AsciiToFull("extend")
#define	KW_IMPORT		AsciiToFull("import")
#define	KW_EXPORT		AsciiToFull("export")
#define	KW_PRECEDENCE		AsciiToFull("precedence")
#define	KW_ASSOC		AsciiToFull("associativity")
#define	KW_LEFT			AsciiToFull("left")
#define	KW_RIGHT		AsciiToFull("right")
#define	KW_BODY			AsciiToFull("body")
#define	KW_FILTER		AsciiToFull("@Filter")
#define	KW_FILTERIN		AsciiToFull("@FilterIn")
#define	KW_FILTEROUT		AsciiToFull("@FilterOut")
#define	KW_FILTERERR		AsciiToFull("@FilterErr")
#define	KW_MACRO		AsciiToFull("macro")
#define	KW_NAMED		AsciiToFull("named")
#define	KW_NEXT			AsciiToFull("@Next")
#define	KW_WIDE			AsciiToFull("@Wide")
#define	KW_HIGH			AsciiToFull("@High")
#define	KW_HSHIFT		AsciiToFull("@HShift")
#define	KW_VSHIFT		AsciiToFull("@VShift")
#define	KW_ONE_COL		AsciiToFull("@OneCol")
#define	KW_ONE_ROW		AsciiToFull("@OneRow")
#define	KW_HSCALE		AsciiToFull("@HScale")
#define	KW_VSCALE		AsciiToFull("@VScale")
#define	KW_SCALE		AsciiToFull("@Scale")
#define	KW_HCONTRACT		AsciiToFull("@HContract")
#define	KW_VCONTRACT		AsciiToFull("@VContract")
#define	KW_HEXPAND		AsciiToFull("@HExpand")
#define	KW_VEXPAND		AsciiToFull("@VExpand")
#define	KW_PADJUST		AsciiToFull("@PAdjust")
#define	KW_HADJUST		AsciiToFull("@HAdjust")
#define	KW_VADJUST		AsciiToFull("@VAdjust")
#define	KW_ROTATE		AsciiToFull("@Rotate")
#define	KW_INCGRAPHIC		AsciiToFull("@IncludeGraphic")
#define	KW_SINCGRAPHIC		AsciiToFull("@SysIncludeGraphic")
#define	KW_GRAPHIC		AsciiToFull("@Graphic")
#define	KW_CASE			AsciiToFull("@Case")
#define	KW_YIELD		AsciiToFull("@Yield")
#define	KW_BACKEND		AsciiToFull("@BackEnd")
#define	KW_XCHAR		AsciiToFull("@Char")
#define	KW_FONT			AsciiToFull("@Font")
#define	KW_SPACE		AsciiToFull("@Space")
#define	KW_BREAK		AsciiToFull("@Break")
#define	KW_COLOUR		AsciiToFull("@SetColour")
#define	KW_COLOR		AsciiToFull("@SetColor")
#define	KW_LANGUAGE		AsciiToFull("@Language")
#define	KW_CURR_LANG		AsciiToFull("@CurrLang")
#define	KW_ENV			AsciiToFull("@LEnv")
#define	KW_CLOS			AsciiToFull("@LClos")
#define	KW_LVIS			AsciiToFull("@LVis")
#define	KW_LUSE			AsciiToFull("@LUse")
#define	KW_OPEN			AsciiToFull("@Open")
#define	KW_USE			AsciiToFull("@Use")
#define	KW_TAGGED		AsciiToFull("@Tagged")
#define	KW_DATABASE		AsciiToFull("@Database")
#define	KW_SYSDATABASE		AsciiToFull("@SysDatabase")
#define	KW_INCLUDE		AsciiToFull("@Include")
#define	KW_SYSINCLUDE		AsciiToFull("@SysInclude")
#define	KW_PREPEND		AsciiToFull("@PrependGraphic")
#define	KW_SYSPREPEND		AsciiToFull("@SysPrependGraphic")
#define	KW_TARGET		AsciiToFull("@Target")
#define	KW_FOLLOWING		AsciiToFull("following")
#define	KW_PRECEDING		AsciiToFull("preceding")
#define	KW_NOW			AsciiToFull("now")
#define	KW_NULL			AsciiToFull("@Null")
#define	KW_GALLEY		AsciiToFull("@Galley")
#define	KW_INPUT		AsciiToFull("@LInput")
#define	KW_SPLIT		AsciiToFull("@Split")
#define	KW_TAG			AsciiToFull("@Tag")
#define	KW_KEY			AsciiToFull("@Key")
#define	KW_CROSS		AsciiToFull("&&")
#define	KW_LBR			AsciiToFull("{")
#define	KW_RBR			AsciiToFull("}")
#define	KW_BEGIN		AsciiToFull("@Begin")
#define	KW_END			AsciiToFull("@End")
#define	KW_VCAT_NN		AsciiToFull("//")
#define	KW_VCAT_MN		AsciiToFull("^//")
#define	KW_VCAT_NJ		AsciiToFull("/")
#define	KW_VCAT_MJ		AsciiToFull("^/")
#define	KW_HCAT_NN		AsciiToFull("||")
#define	KW_HCAT_MN		AsciiToFull("^||")
#define	KW_HCAT_NJ		AsciiToFull("|")
#define	KW_HCAT_MJ		AsciiToFull("^|")
#define	KW_ACAT_NJ		AsciiToFull("&")
#define	KW_ACAT_MJ		AsciiToFull("^&")
#define	KW_MOMENT		AsciiToFull("@Moment")
#define	KW_SECOND		AsciiToFull("@Second")
#define	KW_MINUTE		AsciiToFull("@Minute")
#define	KW_HOUR			AsciiToFull("@Hour")
#define	KW_DAY			AsciiToFull("@Day")
#define	KW_MONTH		AsciiToFull("@Month")
#define	KW_YEAR			AsciiToFull("@Year")
#define	KW_CENTURY		AsciiToFull("@Century")
#define	KW_WEEKDAY		AsciiToFull("@WeekDay")
#define	KW_YEARDAY		AsciiToFull("@YearDay")
#define	KW_DAYLIGHTSAVING	AsciiToFull("@DaylightSaving")


/*@::GetMem(), New(), NewWord(), PutMem(), Dispose()@*************************/
/*                                                                           */
/*  OBJECT GetMem(siz, pos)                                                  */
/*  OBJECT New(typ)                                                          */
/*  OBJECT NewWord(typ, len, pos)                                            */
/*         PutMem(x, siz)                                                    */
/*         Dispose(x)                                                        */
/*                                                                           */
/*  Return a pointer to a new record, of appropriate length (in ALIGNs).     */
/*  The New and NewWord versions initialise LIST, type and rec_size fields.  */
/*  Note that NewWord must be used for WORD and QWORD objects.               */
/*  Dispose x, which is of size siz.  Dispose works out the size itself.     */
/*                                                                           */
/*****************************************************************************/
#define	USES_SIZE ceiling( sizeof(struct uses_type), sizeof(ALIGN) )

#if DEBUG_ON
#define newcount zz_newcount++,
#else
#define newcount
#endif

#define	GetMem(siz, pos)						\
( newcount (zz_size=(siz))>=MAX_OBJECT_REC ?				\
      (OBJECT) Error(1, 1, "word is too long", FATAL, pos)		\
  : zz_free[zz_size] == nil ? zz_hold = GetMemory(zz_size, pos)		\
  : (zz_hold = zz_free[zz_size],					\
	zz_free[zz_size] = pred(zz_hold, CHILD), zz_hold)		\
)

#if DEBUG_ON
#define checknew(typ)							\
  !is_type(typ) ?							\
    Error(1, 2, "New: type %s", INTERN, no_fpos, Image(typ)) :		\
  zz_lengths[typ] == 0 ?						\
    Error(1, 3, "New: zero length!", INTERN, no_fpos) : 0,
#define checkmem(z, typ)						\
  (MemCheck != 0) && ( (int) z == MemCheck) ?				\
      fprintf(stderr, "%d = New(%s)\n", z, Image(type(z))) : 0,
#else
#define checknew(typ)
#define checkmem(z, typ)
#endif

#define	New(typ)							\
( checknew(typ) GetMem(zz_lengths[typ], no_fpos), type(zz_hold) = typ,	\
  checkmem(zz_hold, typ)						\
  pred(zz_hold, CHILD)  = succ(zz_hold, CHILD)  =			\
  pred(zz_hold, PARENT) = succ(zz_hold, PARENT) = zz_hold		\
)

#define NewWord(typ, len, pos)						\
( zz_size = sizeof(struct word_type) - 4 + ((len)+1)*sizeof(FULL_CHAR),	\
  GetMem(ceiling(zz_size, sizeof(ALIGN)), pos),  /* RESETS zz_size */	\
  checkmem(zz_hold, typ)						\
  rec_size(zz_hold) = zz_size,  type(zz_hold) = typ,			\
  pred(zz_hold, CHILD)  = succ(zz_hold, CHILD)  =			\
  pred(zz_hold, PARENT) = succ(zz_hold, PARENT) = zz_hold		\
)

#if DEBUG_ON
#define disposecount zz_disposecount++,
#define	setdisposed  , (MemCheck != 0) && ((int) zz_hold==MemCheck) ?	\
  fprintf(stderr, "Dispose(%d, %s)\n",zz_hold,Image(type(zz_hold))) :	\
  0, type(zz_hold) = DISPOSED
#else
#define disposecount
#define	setdisposed
#endif

#define PutMem(x, siz)							\
( disposecount zz_hold = (x), zz_size = (siz),				\
  pred(zz_hold, CHILD) = zz_free[zz_size], zz_free[zz_size] = zz_hold )

#define Dispose(x)							\
( zz_hold = (x),							\
  assert( pred(zz_hold, CHILD)  == zz_hold, "Dispose: pred(CHILD)!"  ),	\
  assert( succ(zz_hold, CHILD)  == zz_hold, "Dispose: succ(CHILD)!"  ),	\
  assert( pred(zz_hold, PARENT) == zz_hold, "Dispose: pred(PARENT)!" ),	\
  assert( succ(zz_hold, PARENT) == zz_hold, "Dispose: succ(PARENT)!" ),	\
  PutMem(zz_hold, is_word(type(zz_hold)) ? rec_size(zz_hold)		\
			  : zz_lengths[type(zz_hold)]) setdisposed  )

/*@::Append(), Delete(), DeleteAndDispose()@**********************************/
/*                                                                           */
/*  OBJECT Append(x, y, dir)                                                 */
/*                                                                           */
/*  Return the append of lists x and y (dir is PARENT or CHILD).             */
/*                                                                           */
/*****************************************************************************/

#define	Append(x, y, dir)						\
( zz_res = (x),	zz_hold = (y),						\
  zz_hold == nil ? zz_res  :						\
  zz_res  == nil ? zz_hold :						\
  ( zz_tmp = pred(zz_hold, dir),					\
    pred(zz_hold, dir) = pred(zz_res, dir),				\
    succ(pred(zz_res, dir), dir) = zz_hold,				\
    pred(zz_res, dir) = zz_tmp,						\
    succ(zz_tmp, dir) = zz_res						\
  )									\
)


/*****************************************************************************/
/*                                                                           */
/*  OBJECT Delete(x, dir)                                                    */
/*                                                                           */
/*  Delete x from its dir list, and return succ(x, dir) or nil if none.      */
/*                                                                           */
/*****************************************************************************/

#define Delete(x, dir)							\
( zz_hold = (x),							\
  succ(zz_hold, dir) == zz_hold ? nil :					\
  ( zz_res = succ(zz_hold, dir),					\
    pred(zz_res, dir) = pred(zz_hold, dir),				\
    succ(pred(zz_hold, dir), dir) = zz_res,				\
    pred(zz_hold, dir) = succ(zz_hold, dir) = zz_hold,			\
    zz_res								\
  )									\
)

/*****************************************************************************/
/*                                                                           */
/*  OBJECT DeleteAndDispose(x, dir)                                          */
/*                                                                           */
/*  Delete x as above, dispose it, and return succ(x, dir) or nil if none.   */
/*                                                                           */
/*****************************************************************************/

#define DeleteAndDispose(x, dir)					\
( zz_hold = (x),							\
  zz_res  = succ(zz_hold, dir) == zz_hold ? nil :			\
	    ( pred(succ(zz_hold, dir), dir) = pred(zz_hold, dir),	\
	      succ(pred(zz_hold, dir), dir) = succ(zz_hold, dir) ),	\
  pred(zz_hold, dir) = succ(zz_hold, dir) = zz_hold,			\
  Dispose(zz_hold),							\
  zz_res								\
)

#define Down(x)		succ(x, CHILD)
#define NextDown(x)	succ(x, CHILD)
#define LastDown(x)	pred(x, CHILD)
#define PrevDown(x)	pred(x, CHILD)
#define	Up(x)		succ(x, PARENT)
#define	NextUp(x)	succ(x, PARENT)
#define	LastUp(x)	pred(x, PARENT)
#define	PrevUp(x)	pred(x, PARENT)

#define	Child(y, link)							\
for( y = pred(link, PARENT);  type(y) == LINK;  y = pred(y, PARENT) )

#define	Parent(y, link)							\
for( y = pred(link, CHILD);   type(y) == LINK;  y = pred(y, CHILD) )


/*@::UpDim(), DownDim(), Link(), DeleteLink(), etc.@**************************/
/*                                                                           */
/*  UpDim(x, dim)                                                            */
/*  DownDim(x, dim)                                                          */
/*                                                                           */
/*  Returns the dim child or parent link of node x (dim == COL or ROW).      */
/*                                                                           */
/*****************************************************************************/

#define UpDim(x, dim)	( (dim) == COL ? succ(x, PARENT) : pred(x, PARENT) )
#define DownDim(x, dim)	( (dim) == COL ? succ(x, CHILD) : pred(x, CHILD) )


/*****************************************************************************/
/*                                                                           */
/*  OBJECT Link(x, y)                                                        */
/*                                                                           */
/*  Make y a child of x in the directed graph, using a new link.             */
/*  The link node is returned.                                               */
/*                                                                           */
/*****************************************************************************/

#define Link(x, y)							\
( xx_link = New(LINK),							\
  Append(xx_link, (x), CHILD),						\
  Append(xx_link, (y), PARENT)						\
)


/*****************************************************************************/
/*                                                                           */
/*  OBJECT DeleteLink(link)                                                  */
/*                                                                           */
/*  Cut the link between nodes x and y of the directed graph.                */
/*  Returns the link node of the next child of x, or x if none.              */
/*                                                                           */
/*****************************************************************************/

#define DeleteLink(link)						\
( xx_link = (link),							\
  Delete(xx_link, PARENT),						\
  DeleteAndDispose(xx_link, CHILD)					\
)


/*****************************************************************************/
/*                                                                           */
/*  DisposeChild(link)                                                       */
/*                                                                           */
/*  Delete link, and if its child is thereby unattached, dispose it.         */
/*                                                                           */
/*****************************************************************************/

#define DisposeChild(link)						\
( xx_link = (link),							\
  xx_tmp = Delete(xx_link, PARENT),					\
  DeleteAndDispose(xx_link, CHILD),					\
  succ(xx_tmp, PARENT) == xx_tmp ? DisposeObject(xx_tmp) : 0		\
) /* end DisposeChild */


/*****************************************************************************/
/*                                                                           */
/*  MoveLink(link, x, dir)                                                   */
/*                                                                           */
/*  Move the dir end of link from wherever it is now to node x.              */
/*                                                                           */
/*****************************************************************************/

#define MoveLink(link, x, dir)						\
( xx_link = (link),							\
  Delete(xx_link, 1 - (dir) ),						\
  Append(xx_link, (x), 1 - (dir) )					\
) /* end MoveLink */


/*@::TransferLinks(), DeleteNode(), etc.@*************************************/
/*                                                                           */
/*  TransferLinks(start_link, stop_link, dest_link)                          */
/*                                                                           */
/*  Move parent end of links start_link (inclusive) to stop_link (exclusive) */
/*  to just before dest_link.                                                */
/*                                                                           */
/*****************************************************************************/

#define TransferLinks(start_link, stop_link, dest_link)			\
{ OBJECT xxstart = start_link, xxstop = stop_link, xxdest = dest_link;	\
  if( xxstart != xxstop )						\
  {	assert( type(xxstart) == LINK, "TransferLinks: start_link!" );	\
	Append(xxstart, xxstop, CHILD); /* actually a split */		\
	Append(xxstart, xxdest, CHILD);					\
  }									\
}


/*****************************************************************************/
/*                                                                           */
/*  DeleteNode(x)                                                            */
/*                                                                           */
/*  Delete node x and every edge attaching to x.                             */
/*                                                                           */
/*****************************************************************************/

#define DeleteNode(x)							\
{ xx_hold = (x);							\
  while( Up(xx_hold)   != xx_hold ) DeleteLink( Up(xx_hold) );		\
  while( Down(xx_hold) != xx_hold ) DeleteLink( Down(xx_hold) );	\
  Dispose(xx_hold);							\
}


/*****************************************************************************/
/*                                                                           */
/*  MergeNode(x, y)                                                          */
/*                                                                           */
/*  Take all the children of y and make them children of x.                  */
/*  Take all the parents of y and make them parents of x.  Dispose y.        */
/*                                                                           */
/*****************************************************************************/

#define MergeNode(x, y)							\
{ xx_res = (x); xx_hold = (y);						\
  xx_tmp = Delete(xx_hold, PARENT);					\
  Append(xx_res, xx_tmp, PARENT);					\
  xx_tmp = DeleteAndDispose(xx_hold, CHILD);				\
  Append(xx_res, xx_tmp, CHILD);					\
}  /* end MergeNode */


/*****************************************************************************/
/*                                                                           */
/*  ReplaceNode(x, y)                                                        */
/*                                                                           */
/*  Move all the parent links of y to x.                                     */
/*                                                                           */
/*****************************************************************************/

#define ReplaceNode(x, y)						\
( xx_tmp = Delete((y), PARENT),						\
  Append((x), xx_tmp, PARENT)						\
) /* end ReplaceNode */


/*@::FirstDefinite(), NextDefinite(), etc.@***********************************/
/*                                                                           */
/*  FirstDefinite(x, link, y)                                                */
/*                                                                           */
/*  On input, x is an object and link and y are undefined.  On output there  */
/*  are two cases:                                                           */
/*                                                                           */
/*  link != x.  Then y is first definite child of x and link is its link.    */
/*                                                                           */
/*  link == x.  Then x has no definite child and y is undefined.             */
/*                                                                           */
/*  A SPLIT object is considered to be definite if both its children are     */
/*  definite.  This condition is returned by SplitIsDefinite.                */
/*                                                                           */
/*****************************************************************************/

#define FirstDefinite(x, link, y)					\
{ for( link = Down(x);  link != x;  link = NextDown(link) )		\
  { Child(y, link);							\
    if( type(y) == SPLIT ? SplitIsDefinite(y) : is_definite(type(y)) )	\
	break;								\
  }									\
} /* end FirstDefinite */


/*****************************************************************************/
/*                                                                           */
/*  NextDefinite(x, link, y)                                                 */
/*                                                                           */
/*  On input, x is an object and link is a link to one of its children; y    */
/*  is undefined.  On output there are two cases:                            */
/*                                                                           */
/*  link != x.  Then y is the first definite child of x following link, and  */
/*              link is changed to be the link of y.                         */
/*                                                                           */
/*  link == x.  Then x has no definite child following link, and y remains   */
/*              undefined.                                                   */
/*                                                                           */
/*****************************************************************************/

#define NextDefinite(x, link, y)					\
{ for( link = NextDown(link);  link != x;  link = NextDown(link) )	\
  { Child(y, link);							\
    if( type(y) == SPLIT ? SplitIsDefinite(y) : is_definite(type(y)) )	\
	break;								\
  }									\
} /* end NextDefinite */


/*****************************************************************************/
/*                                                                           */
/*  NextDefiniteWithGap(x, link, y, g)                                       */
/*                                                                           */
/*  On input, x is an object and link is a link to one of its children; y    */
/*  and g are undefined.  On output there are two cases:                     */
/*                                                                           */
/*  link != x.  Then y is the first definite child of x following link, and  */
/*              link is changed to be the link of y.  Also, g is defined     */
/*              to be the gap just before y; this must exist and is tested   */
/*              by an assert test.                                           */
/*                                                                           */
/*  link == x.  Then x has no definite child following link, and y and g     */
/*              remain undefined.                                            */
/*                                                                           */
/*****************************************************************************/

#define NextDefiniteWithGap(x, link, y, g)				\
{ g = nil;								\
  for( link = NextDown(link);  link != x;  link = NextDown(link) )	\
  { Child(y, link);							\
    if( type(y) == GAP_OBJ )  g = y;					\
    else if( type(y)==SPLIT ? SplitIsDefinite(y):is_definite(type(y)) )	\
    { assert( g != nil, "NextDefinite: g == nil!" );			\
      break;								\
    }									\
  }									\
} /* end NextDefiniteWithGap */

/*@@**************************************************************************/
/*                                                                           */
/*  LastDefinite(x, link, y)                                                 */
/*                                                                           */
/*  On input, x is an object and link and y are undefined.  On output there  */
/*  are two cases:                                                           */
/*                                                                           */
/*  link != x.  Then y is the last definite child of x and link is its link. */
/*                                                                           */
/*  link == x.  Then x has no definite child and y is undefined.             */
/*                                                                           */
/*  A SPLIT object is considered to be definite if both its children are     */
/*  definite.  This condition is returned by SplitIsDefinite.                */
/*                                                                           */
/*****************************************************************************/

#define LastDefinite(x, link, y)					\
{ for( link = LastDown(x);  link != x;  link = PrevDown(link) )		\
  { Child(y, link);							\
    if( type(y) == SPLIT ? SplitIsDefinite(y) : is_definite(type(y)) )	\
	break;								\
  }									\
} /* end LastDefinite */


/*****************************************************************************/
/*                                                                           */
/*  PrevDefinite(x, link, y)                                                 */
/*                                                                           */
/*  On input, x is an object and link is a link to one of its children; y    */
/*  is undefined.  On output there are two cases:                            */
/*                                                                           */
/*  link != x.  Then y is the first definite child of x preceding link, and  */
/*              link is changed to be the link of y.                         */
/*                                                                           */
/*  link == x.  Then x has no definite child preceding link, and y remains   */
/*              undefined.                                                   */
/*                                                                           */
/*****************************************************************************/

#define PrevDefinite(x, link, y)					\
{ for( link = PrevDown(link);  link != x;  link = PrevDown(link) )	\
  { Child(y, link);							\
    if( type(y) == SPLIT ? SplitIsDefinite(y) : is_definite(type(y)) )	\
	break;								\
  }									\
} /* end PrevDefinite */


/*@::Module Declarations@*****************************************************/
/*                                                                           */
/*  MODULE DECLARATIONS                                                      */
/*                                                                           */
/*****************************************************************************/

/*****  z01.c		Supervise		******************************/
extern			main();			/* main program              */
extern	int		MemCheck;		/* check this memory location*/
extern	OBJECT		StartSym;		/* sym tab entry for \Start  */
extern	OBJECT		GalleySym;		/* sym tab entry for @Galley */
extern	OBJECT		InputSym;		/* sym tab entry for \Input  */
extern	OBJECT		PrintSym;		/* sym tab entry for \Print  */
extern	OBJECT		FilterInSym;		/* sym tab for @FilterIn     */
extern	OBJECT		FilterOutSym;		/* sym tab for @FilterOut    */
extern	OBJECT		FilterErrSym;		/* sym tab for @FilterErr    */
extern	BOOLEAN		AllowCrossDb;		/* true when -s flag absent  */
extern	BOOLEAN		Encapsulated;		/* true when eps wanted      */
extern	BOOLEAN		Kern;			/* true when kerning wanted  */
extern	int		BackEnd;		/* POSTSCRIPT or PLAINTEXT   */
extern	LENGTH		PlainCharWidth;		/* char width if PLAINTEXT   */
extern	LENGTH		PlainCharHeight;	/* char height if PLAINTEXT  */
extern	BOOLEAN		PlainFormFeed;		/* TRUE if use form feed     */
extern	BOOLEAN		InitializeAll;		/* TRUE if initializing run  */
#if LOCALE_ON
extern	nl_catd		MsgCat;			/* error message catalogue   */
#endif

/*****  z02.c		Lexical Analyser	******************************/
extern			LexInit();		/* initialise lex. analyser  */
extern			LexPush();		/* switch to new file list   */
extern			LexPop();		/* return to prev. file list */
extern	BOOLEAN		LexLegalName();		/* check identifier format   */
extern	OBJECT		LexGetToken();		/* get next token from input */
extern			LexScanFilter();	/* scan filter input         */
extern	long		LexNextTokenPos();	/* like ftell() on curr file */

/*****  z03.c		File Service	        ******************************/
extern	FILE_POS	*no_fpos;		/* a null filepos            */
extern			InitFiles();		/* initialize this module    */
extern			AddToPath();		/* add directory to path     */
extern	FILE_NUM	DefineFile();		/* declare input file        */
extern	FILE_NUM	FirstFile();		/* first file of given type  */
extern	FILE_NUM	NextFile();		/* next file of given type   */
extern	FILE_NUM	FileNum();		/* file with given name      */
extern	FULL_CHAR	*FileName();		/* file name of file         */
extern	FULL_CHAR	*EchoFilePos();		/* string value of FILE_POS  */
extern	FULL_CHAR	*EchoFileSource();	/* string value of FILE_POS  */
extern	FULL_CHAR	*EchoFileLine();	/* string value of FILE_POS  */
extern	FILE_POS	*PosOfFile();		/* string of file FILE_POS   */
extern	FILE		*OpenFile();		/* open file for reading     */
extern	FILE		*OpenIncGraphicFile();	/* open @IncludeGraphic file */
extern			FileSetUpdated();	/* declare file updated      */
extern	BOOLEAN		FileTestUpdated();	/* TRUE file file updated    */

/*****  z04.c		Token Service	        ******************************/
extern	OBJECT		NewToken();		/* get a new token           */
extern	OBJECT		CopyTokenList();	/* copy a list of tokens     */
extern	FULL_CHAR	*EchoCatOp();		/* string value of CAT op    */
extern	FULL_CHAR	*EchoToken();		/* returns image of token    */

/*****  z05.c		Read Definitions  	******************************/
extern			ReadPrependDef();	/* read @Prepend ...         */
extern			ReadDatabaseDef();	/* read @Database ...        */
extern			ReadDefinitions();	/* read definitions          */

/*****  z06.c		Object Parser	        ******************************/
extern			InitParser();		/* initialise parser         */
extern			SetScope();		/* set scope for env         */
extern	OBJECT		Parse();		/* parser                    */

/*****  z07.c		Object Service	        ******************************/
extern	OBJECT		MakeWord();		/* a new WORD or QWORD       */
extern	OBJECT		MakeWordTwo();		/* a new WORD from 2 strings */
extern	OBJECT		CopyObject();		/* make a copy of an object  */
extern			DisposeObject();	/* dispose an object         */
extern	BOOLEAN		SplitIsDefinite();	/* TRUE if SPLIT is definite */

/*****  z08.c		Object Manifest	        ******************************/
extern	OBJECT		ReplaceWithTidy();	/* tidy up an object         */
extern	OBJECT		Manifest();		/* manifest an object        */

/*****  z09.c		Closure Expansion	******************************/
extern	OBJECT		SetEnv();		/* build up environment      */
extern			AttachEnv();		/* attach env. to object     */
extern	OBJECT		SearchEnv();		/* search environment        */
extern	OBJECT		GetEnv();		/* retrieve env. from object */
extern	OBJECT		DetachEnv();		/* retrieve and detach env.  */
extern	OBJECT		ClosureExpand();	/* expand a user-def CLOSURE */
extern	OBJECT		ParameterCheck();	/* check expansion of pars   */

/*****  z10.c		Cross References	******************************/
extern			CrossInit();		/* initialize cr record      */
extern			CrossAddTag();		/* add auto tag to closure   */
extern	OBJECT		CrossMake();		/* returns a cross-reference */
extern	OBJECT		GallTargEval();		/* returns the value of a cr */
extern	OBJECT		CrossExpand();		/* returns the value of a cr */
extern			CrossSequence();	/* record cr off root galley */
extern			CrossClose();		/* close down this module    */

/*****  z11.c		Style Service		******************************/
extern			BreakChange();		/* change line spacing       */
extern			SpaceChange();		/* change word spacing       */
extern	FULL_CHAR	*EchoStyle();		/* string value of a style   */

/*****  z12.c		Size Finder		******************************/
extern	OBJECT		MinSize();		/* min. possible size of obj */

/*****  z13.c		Object Breaking		******************************/
extern	OBJECT		BreakObject();		/* break object to fit width */

/*****  z14.c		Object Filling	        ******************************/
extern	OBJECT		FillObject();		/* optimal paragraph breaker */
extern	OBJECT		SimpleFillObject();	/* simple paragraph breaker  */

/*****  z15.c		Size Constraints	******************************/
extern	FULL_CHAR	*EchoConstraint();	/* string value of a constr. */
extern			MinConstraint();	/* take minimum of two const */
extern			EnlargeToConstraint();	/* enlarge obj to constraint */
extern			RotateConstraint();	/* rotate constraints        */
extern			InvScaleConstraint();	/* inverse scale a constr.   */
extern			Constrained();		/* finds size constraint     */
extern			DebugConstrained();	/* debug constraint code     */

/*****  z16.c		Size Adjustments	******************************/
extern	LENGTH		FindShift();		/* shift of @HShift, @VShift */
extern			SetNeighbours();	/* locate definite neighbours*/
extern			AdjustSize();		/* updates sizes if changed  */

/*****  z17.c		Gap Widths		******************************/
extern			GetGap();		/* convert string gap to num */
extern	LENGTH		MinGap();		/* min. possible gap width   */
extern	LENGTH		ExtraGap();		/* extra available gap width */
extern	LENGTH		ActualGap();		/* gap width for output      */
extern	FULL_CHAR	*EchoGap();		/* echo gap (cat. operator)  */

/*****  z18.c		Galley Transfer		******************************/
extern			TransferInit();		/* initialise this module    */
extern	OBJECT		TransferBegin();	/* begin transfer of galley  */
extern			TransferComponent();	/* transfer one component    */
extern			TransferEnd();		/* end galley transfer       */
extern			TransferClose();	/* close this module         */

/*****  z19.c		Galley Attaching	******************************/
extern	OBJECT		SearchGalley();		/* search galley for target  */
extern	int		AttachGalley();		/* start off a galley        */
extern			DetachGalley();		/* detach a galley           */

/*****  z20.c		Galley Flushing		******************************/
extern	FULL_CHAR	*DebugInnersNames();	/* debug names of inners     */
extern			FlushGalley();		/* flush out a galley        */

/***    z21.c		Galley Maker		******************************/
extern			SizeGalley();		/* convert object to galley  */

/***    z22.c		Galley Service		******************************/
extern			FlushInners();		/* flush a list of galleys.  */
extern			ExpandRecursives();	/* expand recursive definite */
extern			Promote();		/* promote components        */
extern			KillGalley();		/* destroy a galley          */
extern			FreeGalley();		/* free a galley to flush    */
extern			Interpose();		/* interpose a VCAT          */
extern	BOOLEAN		TargetSymbol();		/* find target of galley     */
extern	int		CheckConstraint();	/* check ordering constraint */

/*****  z23.c		Galley Printer		******************************/
extern			FixAndPrintObject();	/* fix and print component   */

/*****  z24.c		Print Service           ******************************/
extern			PrintInit();		/* initialise this module    */
extern			PrintBeforeFirst();	/* called before first comp. */
extern			PrintBetween();		/* called between components */
extern			PrintAfterLast();	/* called after last comp.   */
extern			PrintWord();		/* print word at given pos   */
extern			CoordTranslate();	/* translate coord system    */
extern			CoordRotate();		/* rotate coord system       */
extern			CoordScale();		/* scale coord system        */
extern			SaveGraphicState();	/* save coord system etc.    */
extern			RestoreGraphicState();	/* restore coord system etc. */
extern			DefineGraphicNames();	/* define xsize, ysize, etc. */
extern			PrintGraphicObject();	/* print PostScript object   */
extern			PrintGraphicInclude();	/* include PostScript file   */

/*****  z25.c		Object Echo	        ******************************/
extern	FULL_CHAR	*EchoObject();		/* return object as string   */
extern			DebugObject();		/* print object on stderr    */
extern	FULL_CHAR	*EchoIndex();		/* echo galley index         */
extern			DebugGalley();		/* print overview of galley  */

/*****  z26.c		Echo Service	        ******************************/
extern			BeginString();		/* begin string accumulator  */
extern			AppendString();		/* append to current string  */
extern	FULL_CHAR	*EndString();		/* return current string     */
extern	FULL_CHAR	*EchoLength();		/* echo a length             */
extern	FULL_CHAR	*Image();		/* string value of type(x)   */

/*****	z27.c		Debug Service		******************************/
extern			DebugInit();		/* set debug flag            */
extern			Debug();		/* print debug o/p on stderr */
extern			ProfileOn();		/* start profiling           */
extern			ProfileOff();		/* stop profiling            */
extern			ProfilePrint();		/* print profiling results   */

/*****	z28.c		Error Service		******************************/
extern			ErrorInit();		/* initialise log file       */
extern			Error();		/* print error message       */
extern	BOOLEAN		ErrorSeen();		/* TRUE after first error    */
extern			EnterErrorBlock();	/* new error message block   */
extern			LeaveErrorBlock();	/* commit or discard block   */

/*****  z29.c		Symbol Table		******************************/
extern			InitSym();		/* initialize table to empty */
extern			PushScope();		/* push a new scope on stack */
extern			PopScope();		/* pop a scope from stack    */
extern			SuppressVisible();	/* suppress visible flag     */
extern			UnSuppressVisible();	/* unsuppress visible flag   */
extern			SuppressScope();	/* suppress all scoping      */
extern			UnSuppressScope();	/* unsuppress scoping        */
extern			SwitchScope();		/* switch to a saved scope   */
extern			UnSwitchScope();	/* switch back from saved s. */
extern			BodyParAllowed();	/* body par is invokable     */
extern			BodyParNotAllowed();	/* body par is not invokable */
extern	OBJECT		SearchSym();		/* search table for symbol   */
extern	OBJECT		InsertSym();		/* insert a new symbol       */
extern			DeleteEverySym();	/* dispose all symbols       */
extern	FULL_CHAR	*SymName();		/* string name of a symbol   */
extern	FULL_CHAR	*FullSymName();		/* full path name of symbol  */
extern	OBJECT		ChildSym();		/* return a child of a sym   */
extern			CheckSymSpread();	/* check hash table spread   */

/*****  z30.c		Symbol Uses		******************************/
extern			InsertUses();		/* record symbol x uses y    */
extern			FlattenUses();		/* massage uses relation     */
extern	BOOLEAN		SearchUses();		/* retrieve uses info        */
extern	OBJECT		FirstExternTarget();	/* together these return all */
extern	OBJECT		NextExternTarget();	/*   targets of extern galls */

/*****  z31.c		Memory Allocator	******************************/
extern			MemInit();		/* initialise mem. allocator */
extern	OBJECT		GetMemory();		/* get some fresh memory     */
extern			DebugMemory();		/* print memory usage        */
extern	OBJECT		zz_free[];		/* array of free lists       */
extern	unsigned char	zz_lengths[];		/* array of record lengths   */
extern	int		zz_newcount;		/* debug count of News       */
extern	int		zz_disposecount;	/* debug count of Disposes   */
extern	OBJECT		zz_hold;		/* temporary variable only   */
extern	OBJECT		zz_tmp;			/* temporary variable only   */
extern	OBJECT		zz_res;			/* temporary variable only   */
extern	int		zz_size;		/* temporary variable only   */
extern	OBJECT		xx_link, xx_tmp;	/* temporary variable only   */
extern	OBJECT		xx_hold, xx_res;	/* temporary variable only   */

/*****  z32.c		Counter Service		******************************/
extern	OBJECT		Next();			/* increment argument by one */

/*****  z33.c		Database Service	******************************/
extern	OBJECT		OldCrossDb;		/* cross refs from last run  */
extern	OBJECT		NewCrossDb;		/* cross refs from this run  */
extern	OBJECT		DbCreate();		/* create writable database  */
extern			DbInsert();		/* insert into database      */
extern			DbConvert();		/* con. writable to readable */
extern	OBJECT		DbLoad();		/* open readable database    */
extern	BOOLEAN		DbRetrieve();		/* retrieve from database    */
extern	BOOLEAN		DbRetrieveNext();	/* next entry from database  */
extern			DbClose();		/* close a readable database */

/*****  z34.c		Rotation Service    	******************************/
extern			RotateSize();		/* calculate rotated size    */

/*****  z35.c		Time Keeper     	******************************/
extern	OBJECT		MomentSym;		/* the @Moment symbol        */
extern			InitTime();		/* initialize this module    */
extern	OBJECT		StartMoment();		/* a copy of the init time   */
extern	FULL_CHAR	*TimeString();		/* a string containing time  */

/*****  z36.c		Hyphenation     	******************************/
extern	BOOLEAN		ReadHyphTable();	/* read one hyphenation tab  */
extern	OBJECT		Hyphenate();		/* hyphenate a paragraph     */

/*****  z37.c		Font Service             *****************************/
extern	FONT_INFO	*finfo;			/* font metrics information  */
extern	int		font_curr_page;		/* current page number       */
extern			FontInit();		/* intialize this module     */
extern			FontDefine();		/* define a font             */
extern			FontChange();		/* change current font       */
extern			FontWordSize();		/* set sizes of a word       */
extern	LENGTH		FontSize();		/* size of a font            */
extern	LENGTH		FontHalfXHeight();	/* xheight/2 of a font       */
extern	ENCODING	FontEncoding();		/* encoding vector of a font */
extern	FULL_CHAR	*FontName();		/* output name of a font     */
extern	FULL_CHAR	*FontFamilyAndFace();	/* Lout name of a font       */
extern			FontPrintAll();		/* print all font needs      */
extern			FontPrintPageSetup();	/* print all font page setup */
extern			FontPrintPageResources();/* print font page resource */
extern			FontAdvanceCurrentPage();/* advance current page     */
extern	BOOLEAN		FontNeeded();		/* writes out font needs     */

/*****  z38.c		Encoding Vectors	******************************/
extern	ENCODING	EvLoad();		/* load one encoding vector  */
extern	FULL_CHAR	EvRetrieve();		/* convert char name to code */
extern	FULL_CHAR	*EvName();		/* name of encoding vector   */
extern			EvPrintEncodings();	/* print encoding vectors    */
extern			EvPrintResources();	/* print ev resource names   */

/*****  z39.c		String Handler          ******************************/
#define			AsciiToFull(x)		( (FULL_CHAR *) (x) )
#define			StringEqual(a, b) (strcmp((char *)(a), (char *)(b))==0)
#define			StringLessEqual(a, b) (strcmp((char*)(a),(char*)(b))<=0)
#define			StringCat(a, b)		strcat((char *)(a),(char *)(b))
#define			StringCopy(a, b)	strcpy((char *)(a),(char *)(b))
#define			StringLength(a)		strlen((char *)(a))
#define			StringFOpen(a, b)	fopen( (char *) (a), (b) )
#define			StringFPuts(a, b)	fputs( (char *) (a), (b) )
#define			StringFGets(a, b, c)	fgets( (char *) (a), (b), (c) )
#define			StringUnlink(a)		unlink((char *)(a))
#define			StringLink(a, b)	link((char *)(a),(char *)(b))
extern	BOOLEAN		StringBeginsWith();	/* string compare            */
extern	BOOLEAN		StringContains();	/* string search             */
extern	FULL_CHAR	*StringInt();		/* returns integer as string */
extern	FULL_CHAR	*StringFiveInt();	/* returns integer as string */
extern	FULL_CHAR	*StringQuotedWord();	/* returns string in Lout    */

/*****  z40.c		Filter Handler          ******************************/
extern			FilterInit();		/* initialize this module    */
extern	OBJECT		FilterCreate();		/* create a FILTERED object  */
extern			FilterSetFileNames();	/* set @FilterIn etc.        */
extern	OBJECT		FilterExecute();	/* run filter command        */
extern			FilterWrite();		/* write out a filter object */
extern			FilterScavenge();	/* remove used filter files  */

/*****  z41.c		Object Input-Output     ******************************/
extern	OBJECT		ReadFromFile();		/* read object from file     */
extern			AppendToFile();		/* append object to file     */
extern			CloseFiles();		/* close database files      */

/*****  z42.c		Colour Service          ******************************/
extern			ColourInit();		/* initialize colour module  */
extern			ColourChange();		/* change style colour       */
extern	FULL_CHAR	*ColourCommand();	/* command for making colour */

/*****  z43.c		Language Service        ******************************/
extern			LanguageInit();		/* initialize language module*/
extern			LanguageDefine();	/* declare a language        */
extern			LanguageChange();	/* change style language     */
extern	FULL_CHAR	*LanguageString();	/* string value of language  */
extern	OBJECT		LanguageHyph();		/* hyphenation file name     */


/*@::assert(), debug(), debug flags@******************************************/
/*                                                                           */
/*  ASSERT AND DEBUG CODE                                                    */
/*                                                                           */
/*****************************************************************************/

#if ASSERT_ON
#define assert(c, m)							\
   ( (c) ? 0 : Error(1, 4, "assert failed in %s", INTERN, no_fpos, m) )
#else
#define assert(c, m)	0
#endif

#if DEBUG_ON

struct dbs
{	char	*flag;			/* external names for debug flags    */
	BOOLEAN	on[3];			/* the debug flags                   */
};
extern	struct dbs 	dbg[];

/* debug routines */
#define debug0(cat, urg, str)                				\
    if( dbg[cat].on[urg] ) Debug(cat, urg, str); else
#define debug1(cat, urg, str, p1)					\
    if( dbg[cat].on[urg] ) Debug(cat, urg, str, p1); else
#define debug2(cat, urg, str, p1, p2)					\
    if( dbg[cat].on[urg] ) Debug(cat, urg, str, p1, p2); else
#define debug3(cat, urg, str, p1, p2, p3)				\
    if( dbg[cat].on[urg] ) Debug(cat, urg, str, p1, p2, p3); else
#define debug4(cat, urg, str, p1, p2, p3, p4)				\
    if( dbg[cat].on[urg] ) Debug(cat, urg, str, p1, p2, p3, p4); else
#define debug5(cat, urg, str, p1, p2, p3, p4, p5)			\
    if( dbg[cat].on[urg] ) Debug(cat, urg, str, p1, p2, p3, p4, p5); else
#define debug6(cat, urg, str, p1, p2, p3, p4, p5, p6)			\
    if( dbg[cat].on[urg] ) Debug(cat, urg, str, p1, p2, p3, p4, p5, p6); else
#define debug7(cat, urg, str, p1, p2, p3, p4, p5, p6, p7)		\
    if( dbg[cat].on[urg] ) Debug(cat, urg, str, p1, p2, p3, p4, p5,p6,p7); else
#define debug8(cat, urg, str, p1, p2, p3, p4, p5, p6, p7, p8)		\
    if( dbg[cat].on[urg] ) Debug(cat, urg, str, p1, p2,p3,p4,p5,p6,p7,p8); else
#define	ifdebug(cat, urg, x)						\
    if( dbg[cat].on[urg] ) { x; } else 

#define debugcond0(cat, urg, cond, str)                			\
    if( dbg[cat].on[urg] && cond ) Debug(cat, urg, str); else
#define debugcond1(cat, urg, cond, str, p1)				\
    if( dbg[cat].on[urg] && cond ) Debug(cat, urg, str, p1); else
#define debugcond2(cat, urg, cond, str, p1, p2)				\
    if( dbg[cat].on[urg] && cond ) Debug(cat, urg, str, p1, p2); else
#define debugcond3(cat, urg, cond, str, p1, p2, p3)			\
    if( dbg[cat].on[urg] && cond ) Debug(cat, urg, str, p1, p2, p3); else
#define debugcond4(cat, urg, cond, str, p1, p2, p3, p4)			\
    if( dbg[cat].on[urg] && cond ) Debug(cat, urg, str, p1, p2, p3, p4); else
#define debugcond5(cat, urg, cond, str, p1, p2, p3, p4, p5)		\
    if( dbg[cat].on[urg] && cond ) Debug(cat, urg, str, p1, p2, p3, p4, p5); else
#define	ifdebugcond(cat, urg, cond, x)					\
    if( dbg[cat].on[urg] && cond ) { x; } else 
#define	debug_init(str)							\
    DebugInit(str)

/* debug styles */
#define	D	 0
#define	DD	 1
#define	DDD	 2

/* debug flags */
#define	DSP	 1		/*  z01.c   -dsp   Supervise                 */
#define	DLA	 2		/*  z02.c   -dla   Lexical Analyser          */
#define	DFS	 3		/*  z03.c   -dfs   File Service              */
#define	DTS	 4		/*  z04.c   -dts   Token Service             */
#define	DRD	 5		/*  z05.c   -drd   Read Definitions          */
#define	DOP	 6		/*  z06.c   -dop   Object Parser             */
#define	DOS	 7		/*  z07.c   -dos   Object Service            */
#define	DOM	 8		/*  z08.c   -dom   Object Manifest           */
#define	DCE	 9		/*  z09.c   -dce   Closure Expansion         */
#define	DCR	10		/*  z10.c   -dcr   Cross References	     */
#define	DSS	11		/*  z11.c   -dss   Style Service	     */
#define	DSF	12		/*  z12.c   -dsf   Size Finder               */
#define	DOB	13		/*  z13.c   -dob   Object Breaking	     */
#define	DOF	14		/*  z14.c   -dof   Object Filling	     */
#define	DSC	15		/*  z15.c   -dsc   Size Constraints          */
#define	DSA	16		/*  z16.c   -dsa   Size Adjustments	     */
#define	DGW	17		/*  z17.c   -dgw   Gap Widths                */
#define	DGT	18		/*  z18.c   -dgt   Galley Transfer           */
#define	DGA	19		/*  z19.c   -dgf   Galley Attaching          */
#define	DGF	20		/*  z20.c   -dgf   Galley Flushing           */
#define	DGM	21		/*  z21.c   -dgm   Galley Maker              */
#define	DGS	22		/*  z22.c   -dgs   Galley Service            */
#define	DGP	23		/*  z23.c   -dgp   Galley Printer            */
#define	DPS	24		/*  z24.c   -dps   Print Service             */
#define	DOE	25		/*  z25.c   -doe   Object Echo               */
#define	DES	26		/*  z26.c   -des   Echo Service		     */
#define	DZZ	27		/*  z27.c   -dzz   Debug Service             */
#define	DYY	28		/*  z28.c   -dyy   Error Service             */
#define	DST	29		/*  z29.c   -dst   Symbol Table              */
#define	DSU	30		/*  z30.c   -dsu   Symbol Uses               */
#define	DMA	31		/*  z31.c   -dma   Memory Allocator          */
#define	DCS	32		/*  z32.c   -dcs   Counter Service           */
#define	DBS	33		/*  z33.c   -dbs   Database Service          */
#define	DRS	34		/*  z34.c   -drs   Rotation Service          */
#define	DTK	35		/*  z35.c   -dtk   Time Keeper               */
#define	DHY	36		/*  z36.c   -dhy   Hyphenation               */
#define	DFT	37		/*  z37.c   -dft   Font Service              */
#define	DEV	38		/*  z38.c   -dev   Encoding Vectors          */
#define	DSH	39		/*  z39.c   -dsh   String Handler            */
#define	DFH	40		/*  z40.c   -dsh   Filter Handler            */
#define	DIO	41		/*  z41.c   -dio   Object Input-Output       */
#define	DCO	42		/*  z42.c   -dco   Colour Service            */
#define	DLS	43		/*  z43.c   -dls   Language Service          */
#define	DPP	44		/*          -dpp   Profiling                 */
#define	ANY	45		/*          -d     any                       */

#else
#define ifdebug(cat, urg, x)
#define debug0(cat, urg, str)
#define debug1(cat, urg, str, p1)
#define debug2(cat, urg, str, p1, p2)
#define debug3(cat, urg, str, p1, p2, p3)
#define debug4(cat, urg, str, p1, p2, p3, p4)
#define debug5(cat, urg, str, p1, p2, p3, p4, p5)
#define debug6(cat, urg, str, p1, p2, p3, p4, p5, p6)
#define debug7(cat, urg, str, p1, p2, p3, p4, p5, p6, p7)
#define debug8(cat, urg, str, p1, p2, p3, p4, p5, p6, p7, p8)

#define debugcond0(cat, urg, cond, str)
#define debugcond1(cat, urg, cond, str, p1)
#define debugcond2(cat, urg, cond, str, p1, p2)
#define debugcond3(cat, urg, cond, str, p1, p2, p3)
#define debugcond4(cat, urg, cond, str, p1, p2, p3, p4)
#define debugcond5(cat, urg, cond, str, p1, p2, p3, p4, p5)
#define	ifdebugcond(cat, urg, cond, x)
#define	debug_init(str)	Error(1, 5, "%s - debug flags not implemented", \
	FATAL, no_fpos, str)
#endif
