/*##############################################################################

FUNNNELWEB COPYRIGHT
====================
FunnelWeb is a literate-programming macro preprocessor.

Copyright (C) 1992 Ross N. Williams.

   Ross N. Williams
   ross@spam.adelaide.edu.au
   16 Lerwick Avenue, Hazelwood Park 5066, Australia.

This program is free software; you can redistribute it and/or modify
it under the terms of Version 2 of the GNU General Public License as
published by the Free Software Foundation.

This program is distributed WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See Version 2 of the GNU General Public License for more details.

You should have received a copy of Version 2 of the GNU General Public
License along with this program. If not, you can FTP the license from
prep.ai.mit.edu/pub/gnu/COPYING-2 or write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

Section 2a of the license requires that all changes to this file be
recorded prominently in this file. Please record all changes here.

Programmers:
   RNW  Ross N. Williams  ross@spam.adelaide.edu.au

Changes:
   07-May-1992  RNW  Program prepared for release under GNU GPL V2.

##############################################################################*/


/******************************************************************************/
/*                                    DATA.H                                  */
/******************************************************************************/
/*                                                                            */
/* This package (data.h, data.c) contains ALL of the global variables in      */
/* FunnelWeb. Some of the FunnelWeb packages (e.g. the lister) harbour hidden */
/* static state variables which could be considered to be a global variable,  */
/* but, these aside, this package contains all the variables that are used    */
/* directly by more than one package. In many programs, it would likely be    */
/* appropriate to have a separate package for each distinct group of shared   */
/* data so that only those packages needing a particular group of data need   */
/* see it. However, in FunnelWeb's case, the variables are so few, and their  */
/* use so widespread that they are clustered here in one package for all to   */
/* see.                                                                       */
/*                                                                            */
/* This package also contains type definitions for the central FunnelWeb data */
/* structures.                                                                */
/*                                                                            */
/******************************************************************************/

/* Ensure that the body of this header file is included at most once.         */
#ifndef DONE_DATA
#define DONE_DATA

/******************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include "style.h"
#include "clock.h"
#include "list.h"
#include "table.h"
#include "option.h"
#include "section.h"
#include "writfile.h"

/******************************************************************************/
/*                                                                            */
/* DATA TYPES                                                                 */
/* ==========                                                                 */
/* The following section contains all the data types of the global variables. */
/*                                                                            */
/******************************************************************************/

/* The following structure defines a position in the global listing of the    */
/* input data by storing a line number and a column number. The line number   */
/* is a global line number meaning that it increases continuously through     */
/* the lines of included files. The first line is line number 1. The first    */
/* (leftmost) column is column number 1.                                      */
typedef
   struct
     {
      ulong ps_line;
      ulong ps_column;
     } ps_t ;

typedef ps_t *p_ps_t;  /* A pointer to a position is handy too! */

/******************************************************************************/

/* A macro name is represented simply as a character array. */
#define NAME_MAX 80
typedef char name_t[NAME_MAX+1];
typedef name_t *p_name_t;

/******************************************************************************/

/* SC stands for SCrap of text. A scrap of text is a contiguous group of      */
/* printable bytes in memory. The following structure defines such a group by */
/* storing a pointer to the first and last character of the scrap.            */
/* The scrap must contain at least one character (i.e. sc_last>=sc_first).    */
typedef
   struct
     {
      char *sc_first; /* Pointer to the first byte of the scrap.              */
      char *sc_last;  /* Pointer to the last  byte of the scrap.              */
      bool  sc_white; /* TRUE iff the scrap consists entirely of whitespace.  */
     } sc_t;

typedef sc_t *p_sc_t;

/******************************************************************************/

/* LN stands for LiNe. This record holds global and local line numbers as     */
/* well as a scrap that points to the line in question. The scanner (which    */
/* generates this list) guarantees that the last character of the line scrap  */
/* is an EOL.                                                                 */
typedef
   struct
     {
      sc_t  ln_body;    /* Scrap pointing to the line. Line ends in EOL.      */
      ulong ln_global;  /* Global line number of this line.                   */
      ulong ln_local;   /* Local  line number of this line.                   */
     } ln_t;

/* The global line list is simply a list of lines of the following type.      */
typedef p_ls_t p_lnls_t;

/******************************************************************************/

/* The following enumerated type identifies a font. */
#define FT_NORM 1
#define FT_TITL 2
#define FT_STIT 3

/* The following enumerated type identifies a horizontal alignment. */
#define LR_LEFT 1
#define LR_RIGH 2
#define LR_CENT 3

/* We want to pack a font and an alignment into the tk_gen byte of the token  */
/* record (we could create a new field, but as none of the other token kinds  */
/* require an extra field, we choose to pack instead. The formula is this:    */
/* Packed byte=LRFT_PACK*FONT+ALIGNMENT.                                      */
#define LRFT_PACK 10

/******************************************************************************/

/* The following enumerated type identifies the kind of a token. */
#define TK_TEXT  1   /*      Text segment.          */
#define TK_NSEC  2   /*  @A..New section.           */
#define TK_MDEF  3   /*  @$  Macro definition.      */
#define TK_FDEF  4   /*  @F  File definition.       */
#define TK_ONAM  5   /*  @<  Open name.             */
#define TK_CNAM  6   /*  @>  Close name.            */
#define TK_ODEF  7   /*  @{  Open definition.       */
#define TK_CDEF  8   /*  @}  Close definition.      */
#define TK_OPAR  9   /*  @(  Open parameter list.   */
#define TK_CPAR 10   /*  @)  Close parameter list.  */
#define TK_COMA 11   /*  @,  Comma.                 */
#define TK_QUOT 12   /*  @"  Quote.                 */
#define TK_PARM 13   /*  @1  Parameter.             */
#define TK_ZERO 14   /*  @Z  Zero calls allowed.    */
#define TK_MANY 15   /*  @M  Many calls allowed.    */
#define TK_NAME 16   /*  @#  Self contained name.   */
#define TK_EMPH 17   /*  @/  Emphasize text.        */
#define TK_NPAG 18   /*  @t..Newpage.               */
#define TK_TOCS 19   /*  @t..Table of contents.     */
#define TK_SKIP 20   /*  @t..Vertical skip.         */
#define TK_TITL 21   /*  @t..Title text.            */
#define TK_EOF  22   /*      End of file.           */
typedef ubyte tk_k_t;

/* The following structure conveys all the information about a single token.  */
/* As well as the kind of token, the parser needs to know where the token is  */
/* in the input file and what the text of the token is if it is a text token. */
/* Some other tokens have a numeric attribute associated with them and the    */
/* tk_gen field provides a place for this. The attributes are:                */
/*    TK_PARM - The number of the parameter [1,9].                            */
/*    TK_NAME - The number of the character forming the name [0,255].         */
/*    TK_NSEC - The level of the section [0,5]. 0=@*, 1=@A, 2=@B,..,5=@E.     */
/*    TK_SKIP - Number of millimetres to skip vertically [0,255].             */
/*    TK_TITL - Font and alignment packed into byte as specified earlier.     */
/*              tk_sc is the text to be set as a title.                       */
typedef
   struct
     {
      tk_k_t tk_kind;  /* Kind of this token.                                 */
      ps_t   tk_ps;    /* Position of the first character of this token.      */
      sc_t   tk_sc;    /* Scrap constituting token.                           */
      ubyte  tk_gen;   /* General token attribute.                            */
     } tk_t;

typedef p_ls_t p_tkls_t;  /* A list of tokens. */

/******************************************************************************/

typedef p_ls_t p_scls_t;  /* List of scraps.                                  */
typedef p_ls_t p_scll_t;  /* List of list of scraps =TEXT.                    */

typedef p_ls_t p_ells_t;  /* List of pointers to elements = EXPRESSION.       */
typedef p_ls_t p_elll_t;  /* List of list of pointers to elements.            */
typedef p_ls_t p_ell3_t;  /* List of list of list of pointers to elements.    */

/******************************************************************************/

/* This structure's signature is BP for Body Part. FunnelWeb macros can       */
/* be defined in a series of "+=" definitions scattered through the input     */
/* file. The definition of the macro is the concatenation of all the parts.   */
/* The contributory part of a part consists of a single expression.           */
/* Throughout the document, body parts (definition parts) are numbered        */
/* sequentially by a sequence number.                                         */
typedef
   struct
    {
     p_ells_t bp_ex;  /* Expression that is logically appended to definition. */
     ulong    bp_seq; /* Sequence number of body part.                        */
     ps_t     bp_ps;  /* Position at which the definition appears.            */
    } bp_t;

typedef bp_t *p_bp_t;

/* A list of body parts constitutes the full body of a macro. */
typedef p_ls_t p_bpls_t;

/******************************************************************************/

/* The following structure summarizes a macro CALL. Each macro table entry    */
/* contains a field ma_calls which contains a list of these structures. The   */
/* list is used to generate diagnostics (e.g. if a call has the wrong number  */
/* of parameters) and also to give cross reference information in the typeset */
/* documentation.                                                             */
typedef
   struct
     {
      ulong mc_seq;   /* Sequence number of body part containing call.        */
      ps_t  mc_ps;    /* Position at which the call occurred.                 */
      ulong mc_npar;  /* Number of parameters in call.                        */
     } mc_t;

typedef mc_t *p_mc_t;

/* A list of calls summarizes the entire usage of a macro in a document.      */
typedef p_ls_t p_mcls_t;

/******************************************************************************/

/* This structure stores the definition of a single macro. The first field    */
/* md_isdef indicates whether a definition for this macro has so far been     */
/* seen. If it has, md_isdef=TRUE and the remaining fields are well defined.  */
typedef
   struct
     {
      bool     md_isdef;  /* TRUE iff the macro is defined.                   */
      ps_t     md_ps;     /* isdef=> Position of first definition part.       */
      ubyte    md_npar;   /* isdef=> Number of params specified in defn.      */
      bool     md_isadd;  /* isdef=> TRUE iff additively defined.             */
      bool     md_iszer;  /* isdef=> TRUE iff zero calls allowed.             */
      bool     md_isman;  /* isdef=> TRUE iff many calls allowed.             */
      bool     md_isfil;  /* isdef=> TRUE iff macro is bound to an outp file. */
      p_bpls_t md_body;   /* isdef=> Body of the macro (list of parts).       */
     } md_t;

/******************************************************************************/

/* The following structure contains the full information about a macro.       */
typedef
   struct
     {
      name_t   ma_name;   /* Name of the macro.                               */
      p_mcls_t ma_calls;  /* List of calls of this macro in the document.     */
      md_t     ma_defn;   /* Definition of this macro.                        */
      p_ell3_t ma_actn;   /* Used by tangle. List of actual parameter lists.  */
      uword    ma_level;  /* Used by analyser. Depth of deepest call.         */
     } ma_t;

/* A pointer to the comprehensive macro structure defined above is the way    */
/* that FunnelWeb refers to macros internally.                                */
typedef ma_t *p_ma_t;

/******************************************************************************/

/* An expression consists of a sequence of ELEMENTS each of which can         */
/* be one of three kinds:                                                     */
/*                                                                            */
/*    1. A block of text.                                                     */
/*    2. An invocation of another macro.                                      */
/*    3. A parameter of the current macro.                                    */
/*                                                                            */
/* The following enumerated type identifies one of these three alternatives.  */
#define EL_TEXT 1
#define EL_INVC 2
#define EL_PARM 3
typedef ubyte el_k_t;

/* The following rather messy structure contains information about a single   */
/* element. As mentioned above, an element can be one of three kinds and the  */
/* following structure should, strictly speaking, be defined as a C union so  */
/* as to emphasize the mutually exclusive nature of most of its fields.       */
/* At one stage this structure did contain a union, however, it introduced    */
/* more mess than it brought clarity (because of the extra two subnames) and  */
/* was eventually dropped.                                                    */
/* A few fields deserve some explanation:                                     */
/*    el_pretx and el_postx hold the exact whitespace appearing between       */
/*       actual parameters in a macro call. This enables the call to be       */
/*       formatted properly in the typeset output.                            */
/*    el_which is part of the macro parameter element (e.g. @1) and points to */
/*       the macro within which the @1 appears. Strictly speaking this should */
/*       not be necessary, but it is convenient for the tangler to have this  */
/*       information when it is half way through expanding an expression.     */
typedef
   struct
     {
      el_k_t   el_kind;  /* Indicates what kind of element structure holds.   */

      p_scls_t el_text;  /* EL_TEXT => List of scraps forming a text chunk.   */

      p_ma_t   el_p_mac; /* EL_INVC => Pointer to macro being invoked.        */
      p_elll_t el_parls; /* EL_INVC => List of actual parameters.             */
      p_scll_t el_pretx; /* EL_INVC => Text before each parameter.            */
      p_scll_t el_postx; /* EL_INVC => Text after  each parameter.            */

      p_ma_t   el_which; /* EL_PARM => Macro in which this element appears.   */
      ubyte    el_parno; /* EL_PARM => Parameter number of this actual param. */
     } el_t;

typedef el_t *p_el_t;

/******************************************************************************/

/* A document component (represented by the DC_ data structures (see below)   */
/* can be one of three things: a lump of text, a typesetter-generic           */
/* typesetting directive, or a macro definition. The second of these consists */
/* of a whole collection of typesetting commands and so rather than           */
/* cluttering up the dc_ record, they have been separated out here.           */
#define TY_NSEC 1   /* New section.                                           */
#define TY_OLIT 2   /* Open  literal.                                         */
#define TY_CLIT 3   /* Close literal.                                         */
#define TY_OEMP 4   /* Open  emphasise.                                       */
#define TY_CEMP 5   /* Close emphasise.                                       */
#define TY_NPAG 6   /* New page.                                              */
#define TY_TOCS 7   /* Table of contents.                                     */
#define TY_SKIP 8   /* Skip vertical.                                         */
#define TY_TITL 9   /* Title.                                                 */
typedef ubyte ty_k_t;

typedef
   struct
     {
      ty_k_t   ty_kind;  /* Kind of this typesetting directive.               */
      sn_t     ty_sn;    /* TY_NSEC=> Hierarchical section number.            */
      bool     ty_isnam; /* TY_NSEC=> TRUE iff the section is named.          */
      name_t   ty_name;  /* TY_NSEC=> ty_isnam=> Name of section.             */

      uword    ty_mm;    /* TY_SKIP=> Millimetres to skip.                    */

      ubyte    ty_font;  /* TY_TITL=> Font in which to write title.           */
      ubyte    ty_align; /* TY_TITL=> Alignment with which to write title.    */
      sc_t     ty_sc;    /* TY_TITL=> Scrap that is title text.               */
     } ty_t;

typedef ty_t *p_ty_t;

/******************************************************************************/

/* The document list contains a representation of the input document in the   */
/* form in which it was fed to FunnelWeb. This structured representation of   */
/* the input is used by the weaver to generate the typeset output.            */
/* Here, a document is represented by a list of DOCUMENT COMPONENTs (DC) each */
/* of which contains information about a major chunk of the document. The     */
/* following enumerated type dc_k_t (document component kind type) is used to */
/* indicate which kind of component each list element contains.               */
#define DC_TEXT 1   /* Text component consists of a block of text.            */
#define DC_TYPE 2   /* Typesettting component affecting document typesetting. */
#define DC_MACR 3   /* A MACRo definition.                                    */
typedef ubyte dc_k_t;

/* The following structure stores a single document component. Like the el_t  */
/* type, the dc_t type should really be a union type, but a union construct   */
/* has been avoided to make the naming simpler.                               */
typedef
   struct
     {
      ps_t     dc_ps;    /* Position of this component.                       */
      dc_k_t   dc_kind;  /* Kind of this component.                           */

      p_scls_t dc_text;  /* DC_TEXT=> Text segment constituting this compnt.  */

      ty_t     dc_ty;    /* DC_TYPE=> Typesetting object record.              */

      p_ma_t   dc_p_ma;  /* DC_MACR=> Pointer to the macro defined.           */
      ulong    dc_part;  /* DC_MACR=> Part number of this part of macro defn. */
     } dc_t;

typedef dc_t *p_dc_t;

/* A list of document components constitutes the global document list         */
/* declared later.                                                            */
typedef p_ls_t p_dcls_t;

/******************************************************************************/

/* This enumerated type identifies a typesetter.                              */
/*    TR_NONE - No specific typesetter specified.                             */
/*    TR_TEX  - The TeX typesetter.                                           */
#define TR_NONE 1
#define TR_TEX  2
/* Add more typesetters here later. */
typedef ubyte tr_k_t;


/******************************************************************************/
/*                                                                            */
/* VARIABLES                                                                  */
/* =========                                                                  */
/* This section contains external declarations of the global variables.       */
/* The global variables themselves appear in DATA.C.                          */
/*                                                                            */
/******************************************************************************/

/* This #ifndef is part of a mechanism that makes the following definitions   */
/* visible to other modules declared as "extern", and visible to data.c       */
/* declared as ordinary declarations. This prevents inconsistencies.          */
#ifndef EXTERN
#define EXTERN extern
#endif

/* This global options variable holds the options that were transmitted to    */
/* FunnelWeb proper through the command line.                                 */
EXTERN GLOVAR op_t option;

/* The following option variable is set by the scanner and is used by the     */
/* tangler. It determines whether the tangler will use natural indenting.     */
/* TRUE => Tangler should use space indenting. FALSE=>No indenting.           */
EXTERN GLOVAR bool tgindent;

/* The following option variable is set by the scanner and is used by the     */
/* tangler. It sets a limit on the length of the lines of the product files   */
/* generated by tangle. A value of TGMAXINF indicates that no checking need   */
/* be performed.                                                              */
#define TGMAXINF (ULONG_MAX)
EXTERN GLOVAR ulong tglinmax;

/* The following variable is written by the scanner and read by weave. It     */
/* stores the typesetter format possibly specified by the user in the input.  */
EXTERN GLOVAR tr_k_t tr_codes;

/* The following five lists and tables constitute the major data structures   */
/* that are communicated between the major components of FunnelWeb.           */
/* The TOKEN_LIST contains a tokenized representation of the input file.      */
/* The LINE_LIST contains a list of the lines of the input file.              */
/* The DOCUMENT_LIST contains a structured representation of the input file.  */
/* The MACRO_TABLE describes the macros defined in the input file.            */
/* The FILE_TABLE identifies macros that are connected to product files.      */
/*                                        Created By  Used By                 */
/*                                        ----------  -------                 */
EXTERN GLOVAR p_tkls_t token_list;     /*    Scanner  Parser                  */
EXTERN GLOVAR p_lnls_t line_list;      /*    Scanner  Lister                  */
EXTERN GLOVAR p_dcls_t document_list;  /*     Parser  Weaver                  */
EXTERN GLOVAR p_tb_t   macro_table;    /*     Parser  Tangler, Weaver         */
EXTERN GLOVAR p_tb_t   file_table;     /*     Parser  Tangler, Weaver         */

/* Three output streams are accessible globally.                              */
/* The SCREEN FILE is connected to standard output (the user screen).         */
/* The JOURNAL FILE logs FunnelWeb command language transactions.             */
/* The LISTING FILE is created by an single invocation of FunnelWeb proper.   */
EXTERN GLOVAR wf_t f_s;  /* Screen  file. */
EXTERN GLOVAR wf_t f_j;  /* Journal file. */
EXTERN GLOVAR wf_t f_l;  /* Listing file. */

/* Many of the FunnelWeb IO functions accept a single string as a parameter.  */
/* This means that sprintf and a temporary string must be used in order to    */
/* produce parameterized formatted output. Rather than declare temporary      */
/* strings in each local function, we declare them globally.                  */
EXTERN GLOVAR char linet1[2000];

/* Definitions of Diagnostic Levels                                           */
/* --------------------------------                                           */
/* A WARNING has no effect except to cause a message to be issued.            */
/* An ERROR causes FunnelWeb to abort to the shell at the end of the phase.   */
/*    Example: An error during scanning means that the FunnelWeb run will     */
/*    terminate to the shell at the end of the scanning phase.                */
/* A SEVERE ERROR causes FunnelWeb to abort to the shell immediately.         */
/* A FATAL ERROR causes FunnelWeb to abort to the OS immediately.             */

/* The following variables count diagnostics over a single FunnelWeb run.     */
EXTERN GLOVAR ulong num_war;  /* Number of      warnings.                     */
EXTERN GLOVAR ulong num_err;  /* Number of        errors.                     */
EXTERN GLOVAR ulong num_sev;  /* Number of severe errors.                     */

/* The following variables count diagnostics over multiple FunnelWeb runs.    */
EXTERN GLOVAR ulong sum_war;  /* Number of      warnings.                     */
EXTERN GLOVAR ulong sum_err;  /* Number of        errors.                     */
EXTERN GLOVAR ulong sum_sev;  /* Number of severe errors.                     */
EXTERN GLOVAR ulong sum_fat;  /* Number of fatal  errors.                     */

/******************************************************************************/

/* For #ifndef preventing multiple inclusion of the body of this header file. */
#endif

/******************************************************************************/
/*                                 End of DATA.H                              */
/******************************************************************************/
