/*************************************************
*    The PMW Music Typesetter - 3rd incarnation  *
*************************************************/

/* Copyright (c) Philip Hazel, 1991 - 2020 */

/* Written by Philip Hazel, starting November 1991 */
/* This file last modified: November 2020 */

/* This is the main header file, imported by all other sources. */


/* ANSI C includes */

#include <ctype.h>
#include <math.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

/* Unix includes */

#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>

/* Optionsl B2PF include */

#ifdef SUPPORT_B2PF
#include <b2pf.h>
#endif

/* Debugging */

#define DEBUG(x) if (debugging) debug_printf x


/*************************************************
*                Program parameters              *
*************************************************/

#define B2PF_STACKBSIZE    2000   /* On-stack buffer size */
#define DEF_MAX_BARS        500   /* Default max bars per movement */
#define DEF_MAX_MOVEMENTS    50   /* Default max movements */
#define DRAW_BLOCKSIZE      256   /* Chunk size for draw routines */
#define DRAW_STACKSIZE      100   /* Size of draw stack */
#define LAYOUT_MAXSIZE      200   /* Max items in layout list */
#define MAX_BEAMSIZE        100   /* Should be large enough for anything */
#define MAX_CHORDSIZE        16   /* 16-note chords should be enough */
#define MAX_DRAW_VARIABLE    19   /* Max number of a draw variable */
#define MAX_FONTS            50   /* Maximum number of different fonts */
#define MAX_INCLUDE          10   /* Max depth of included files */
#define MAX_MACROARGS        20   /* Max number of macro arguments */
#define MAX_MACRODEFAULT    256   /* Max length of macro default argument */
#define MAX_POSTABLESIZE    400   /* Max number of entries */
#define MAX_UTRANSLATE     1000   /* Max Unicode translations for a font */
#define MAX_XKEYS            10   /* Max number of custom keys (must be <= 21)*/
#define MIDI_MAXCHANNEL      16   /* Maximum MIDI channel number */
#define READ_BUFFERSIZE    2000   /* Input buffer size */
#define TEXT_QUEUE_SIZE      50   /* Max texts before a note */
#define WORD_BUFFERSIZE     256   /* Buffer for reading words */


/* Maximum stave is defined in terms of the length of the bit vector
that maps stave presence, suspension, etc. If STAVE_BITVEC_SIZE is
increased, some tables in tables.c must also be extended. Also, the
mac_initstave, mac_anystave and mac_samestave macros below must be
suitably modified. */

#define STAVE_BITVEC_SIZE     2   /* Number of ints in the bit vector */
#define MAX_STAVE             (STAVE_BITVEC_SIZE * 32 - 1)

/* Typesetting parameters */

#define PAGE_LEFTBARSPACE  8000   /* Space at left of bar */


/*************************************************
*  Macros etc for types and character handling   *
*************************************************/

/* Some operating systems (naughtily, imo) include a definition for "uchar" in
the standard header files, so we use "uschar". Solaris has u_char in
sys/types.h. This is just a typing convenience, of course. */

typedef unsigned char uschar;
typedef unsigned int  usint;

/* These macros save typing for the casting that is needed to cope with the
mess that is "char" in ISO/ANSI C. */

#define CS   (char *)
#define CSS  (char **)
#define US   (unsigned char *)
#define USS  (unsigned char **)

/* The C library string functions expect "char *" arguments. Use macros to
avoid having to write a cast each time. We do this for string and file
functions; for other calls to external libraries (which are on the whole
special-purpose) we just use casts. */

#define Uatoi(s)           atoi(CS(s))
#define Ufgets(b,n,f)      fgets(CS(b),n,f)
#define Ufopen(s,t)        fopen(CS(s),CS(t))
#define Ufputs(b,f)        fputs(CS(b),f)
#define Ustrcat(s,t)       strcat(CS(s),CS(t))
#define Ustrchr(s,n)       US strchr(CS(s),n)
#define Ustrcmp(s,t)       strcmp(CS(s),CS(t))
#define Ustrcpy(s,t)       strcpy(CS(s),CS(t))
#define Ustrlen(s)         (int)strlen(CS(s))
#define Ustrncat(s,t,n)    strncat(CS(s),CS(t),n)
#define Ustrncmp(s,t,n)    strncmp(CS(s),CS(t),n)
#define Ustrncpy(s,t,n)    strncpy(CS(s),CS(t),n)
#define Ustrstr(s, t)      US strstr(CS(s),CS(t))
#define Ustrtol(s,t,b)     strtol(CS(s),CSS(t),b)
#define Ustrtoul(s,t,b)    strtoul(CS(s),CSS(t),b)

/* Define boolean types here so they can be used in included headers */

#define BOOL  int
#define CBOOL char

/* The following value (LOWCHARLIMIT) must not be less than 256. Characters
whose Unicode values are less than this limit are treated specially in two
ways:

(1) Each font has a table of widths of this size, so that the widths of the
most common characters can be found quickly. Characters whose code points are
greater than this limit have their widths stored in a tree structure instead.

(2) Cloned PostScript fonts are created, with different encodings, so that
characters up to this value can be directly printed without much translation.
NOTE: At present, we assume that the value is less than 512, because only two
fonts are used. It seems unlikely that we will ever need to extend this, but
you never know. */

#define LOWCHARLIMIT     384

/* These define the characters that are substituted for unavailable characters,
in standardly encoded and non-standardly encoded fonts, respectively. The first
should be one that is always available in the base font, with code less that
256, because it is used unmodified in the PostScript output. */

#define UNKNOWN_CHAR_S   0x00a4    /* Currency symbol */
#define UNKNOWN_CHAR_N   0x00b4    /* Triangle in Music, multiply in Symbol */

/* Other specific Unicode characters that are needed */

#define QUOTE_LEFT       0x2018
#define QUOTE_RIGHT      0x2019
#define CHAR_FI          0xfb01    /* fi ligature */

/* Macros for loading UTF-8 characters */

/* Get the next UTF-8 character, not advancing the pointer. */

#define GETCHAR(c, ptr) \
  c = *ptr; \
  if ((c & 0xc0) == 0xc0) \
    { \
    int gcii; \
    int gcaa = utf8_table4[c & 0x3f];  /* Number of additional bytes */ \
    int gcss = 6*gcaa; \
    c = (c & utf8_table3[gcaa]) << gcss; \
    for (gcii = 1; gcii <= gcaa; gcii++) \
      { \
      gcss -= 6; \
      c |= (ptr[gcii] & 0x3f) << gcss; \
      } \
    }

/* Get the next UTF-8 character, advancing the pointer. */

#define GETCHARINC(c, ptr) \
  c = *ptr++; \
  if ((c & 0xc0) == 0xc0) \
    { \
    int gcaa = utf8_table4[c & 0x3f];  /* Number of additional bytes */ \
    int gcss = 6*gcaa; \
    c = (c & utf8_table3[gcaa]) << gcss; \
    while (gcaa-- > 0) \
      { \
      gcss -= 6; \
      c |= (*ptr++ & 0x3f) << gcss; \
      } \
    }


/*************************************************
*     Structures used in barhdr.h                *
*************************************************/

/* We need to define certain structures before including barhdr.h. Other
structures are defined later, below. */


/* Structure for describing a text item used in drawing functions */

typedef struct {
  int   ident;
  int   rotate;
  int   xdelta;
  int   ydelta;
  uschar *text;
  short int flags;
  short int size;
} drawtextstr;

/* Structure for items in encoded draw function vectors, variables, and stack.
A union is needed for the value because some are integers and some are
addresses. They used to be punned, stuffing pointers into ints, but this
doesn't work in 64-bit environments. */

typedef struct {
  usint dtype;             /* data type, eg dd_number */
  union {
    void *ptr;
    int   val;
  } d;
} drawitem;

/* Types of value in draw programs, stacks, and variables; used in the dtype
field in the structure above for items on the stack and for variables. */

#define dd_any      1      /* Used in the checklist for any type allowed */
#define dd_number   2
#define dd_text     3
#define dd_code     4
#define dd_varname  5

/* Structure for each node in a tree */

typedef struct tree_node
  {
  struct tree_node *left;         /* pointer to left child */
  struct tree_node *right;        /* pointer to right child */
  uschar *name;                   /* node name */
  uschar *data;                   /* for string values */
  int    val[3];                  /* for numeric values */
  uschar balance;                 /* balancing factor */
  }
tree_node;

/* One heading/footing/footnote. There are three different cases: a text
string, a drawing, or a PostScript string. They use different subsets of the
fields in this structure. */

typedef struct headstr {
  struct headstr *next;
  int  size;           /* Font size: 0 => PostScript; < 0 => drawing */
  int  space;          /* Space to follow; must be 0 except for text */
  uschar *text;        /* String for text or PostScript */
  /* --- Text string --- */
  int *matrix;         /* points to transformation or NULL */
  int  font;           /* initial font */
  int  stretch;        /* amount to stretch spaces by */
  int  spaceabove;     /* space above the line of text */
  /* --- Drawing --- */
  tree_node *drawing;  /* pointer to the drawing */
  drawitem *drawargs;  /* drawing arguments */
} headstr;

/* Text associated with a line or slur gap */

typedef struct {
  uschar *text;
  short int flags;
  short int size;
  int x;
  int y;
} gaptextstr;


/* Bar structures are held separately for convenience */

#include "barhdr.h"



/*************************************************
*                  Global Macros                 *
*************************************************/

#define FALSE          0
#define TRUE           1

#define BIGNUMBER      0x7FFFFFFF

#define rc_noerror     0   /* Return codes */
#define rc_warning     1
#define rc_serious     2
#define rc_failed      3

#define time_common  255
#define time_cut     254


/* If MaxExtraFont is increased, check that font_IdStrings in tables.c contains
sufficient identifying strings, and that ps_IdStrings in ps.c is of the right
size too. If MaxFontSizes is changed, the initializing table init_fontsizes in
tables.c must be made to be the correct size. */

#define MaxFontSizes   20   /* for different text sizes */
#define MaxExtraFont   12   /* for different faces */


/* It is helpful to have names for the vertical offsets of the various lines
and spaces on the stave. The bottom line is numbered one. These pitches are the
appropriate vertical offsets from the bottom line to print a note or an
accidental on the relevant line or space. */

#define L_0L       -6000
#define L_0S       -4000
#define L_1L       -2000
#define L_1S           0
#define L_2L        2000
#define L_2S        4000
#define L_3L        6000
#define L_3S        8000
#define L_4L       10000
#define L_4S       12000
#define L_5L       14000
#define L_5S       16000
#define L_6L       18000


/* Similarly, it is helpful to have names for the equivalent stave pitches. */

#define P_0L     124
#define P_0S     126
#define P_1L     128
#define P_1S     130
#define P_2L     132
#define P_2S     134
#define P_3L     136
#define P_3S     138
#define P_4L     140
#define P_4S     142
#define P_5L     144
#define P_5S     146
#define P_6L     148


/* Flags for diffent kinds of text - 16-bit field */

#define text_ul         0x0001
#define text_fb         0x0002
#define text_above      0x0004
#define text_box        0x0008
#define text_endalign   0x0010
#define text_middle     0x0020
#define text_ps         0x0040
#define text_rehearse   0x0080
#define text_ring       0x0100
#define text_baralign   0x0200
#define text_atulevel   0x0400
#define text_absolute   0x0800
#define text_centre     0x1000
#define text_timealign  0x2000
#define text_followon   0x4000

/* Flags for stave name texts */

#define snf_vcentre     0x01
#define snf_hcentre     0x02
#define snf_rightjust   0x04
#define snf_vertical    0x08

/* Clef style flags */

#define clef_oldbass    0x01
#define clef_oldalto    0x02

/* A maximum is set for transposition - 5 octaves should be ample - and a
conventional value for "no transposition". */

#define max_transpose   60
#define no_transpose  1000

/* Names for C major and the special key 'N', which behaves like C major (no
key signature) but does not transpose. There are 42 normal keys (7 letters
times 2 modes times 3 accidentals) whose values are 0-41. There are also up to
MAX_XKEYS custom-defined keys, starting at 43. Note that the 64-bit is used in
some contexts to indicate "reset with naturals". */

#define C_key   2
#define N_key  42  /* The answer to life, the universe, and everything. */
#define X_key  43  /* The first custom key */



/*************************************************
*              Global procedure macros           *
*************************************************/

#define ROUND(x) ((((x) + sizeof(void *) - 1)/sizeof(void *)) * sizeof(void *))

#define mac_fdiv(f,d) ((int)(((double)(f) * 1000.0)/((double) (d))))

#define mac_muldiv(a,b,c) \
  ((int)((((double)((int)(a)))*((double)((int)(b))))/((double)((int)(c)))))

#define mac_setstavesize(i) \
  main_stavemagn = (curmovt->stavesizes)[i]

#define mac_advancechord(ww) \
  if ((ww = (b_notestr *)((uschar *)ww + length_table[b_note]))->type == b_Jump) \
    ww = (b_notestr *) \
      ((uschar *)(((b_Jumpstr *)ww)->next) + length_table[b_Jump])

#define mac_couplepitch(p, f) \
  if ((f & (nf_coupleU | nf_coupleD)) != 0) \
    p += (((f & nf_coupleU) != 0)? (out_upgap - 24):(24 - out_downgap))

#define mac_clearstave(a, z) \
  a[z >> 5] &= ~main_bit[z & 0x1f]

/* Needs manual adjustment when STAVE_BITVEC_SIZE changes */
#define mac_initstave(a, b) \
  a[0] = a[1] = (usint)b

#define mac_setstave(a, z) \
  a[z >> 5] |= main_bit[z & 0x1f]

/* Test for the presence of a stave a bitmap */
#define mac_teststave(a, z) \
  ((a[z >> 5] & main_bit[z & 0x1f]) != 0)

/* Test for the absence of a stave a bitmap */
#define mac_testNstave(a, z) \
  ((a[z >> 5] & main_bit[z & 0x1f]) == 0)

/* Test for the presence of a stave in both of two bitmaps */
#define mac_teststave2(a, b, z) \
  ((a[z >> 5] & b[z >> 5] & main_bit[z & 0x1f]) != 0)

/* Test for the absence of a stave in at least one of two bitmaps */
#define mac_testNstave2(a, b, z) \
  ((a[z >> 5] & b[z >> 5] & main_bit[z & 0x1f]) == 0)

/* Needs manual adjustment when STAVE_BITVEC_SIZE changes */
#define mac_anystave(a) \
  ((a[0] | a[1]) != 0)

/* Needs manual adjustment when STAVE_BITVEC_SIZE changes */
#define mac_diffstave(a, b) \
  (a[0] != b[0] || a[1] != b[1])

/* Needs manual adjustment when STAVE_BITVEC_SIZE changes */
#define mac_samestave(a, b) \
  (a[0] == b[0] && a[1] == b[1])



/*************************************************
*               Global enumerations              *
*************************************************/

/* Stem swap options */

enum { stemswap_default, stemswap_up, stemswap_down, stemswap_left,
       stemswap_right };

/* Justification values */

enum { just_top = 1, just_bottom = 2, just_left = 4, just_right = 8,
       just_all = just_top+just_bottom+just_left+just_right };

/* Clefs - real ones come first, and clef_count is the number of
different ones. */

enum { clef_treble,      clef_soprano,      clef_mezzo,
       clef_alto,        clef_tenor,        clef_cbaritone,
       clef_baritone,    clef_bass,         clef_deepbass,
       clef_h,           clef_none,         clef_trebledescant,
       clef_trebletenor, clef_trebletenorB, clef_soprabass,
       clef_contrabass,  clef_count};

/* Movement options */

enum { movt_default, movt_newpage, movt_thispage, movt_thisline,
       movt_nopageheading = 0x0100, movt_uselastfooting = 0x0200 };

/* Skip options for errors */

enum { skip_OFF, skip_EOL, skip_KET, skip_BACKSLASH, skip_BAR };

/* Notehead type options. If these are changed, the tables in
shownote.c must also be changed. No stems are printed for values
greater than or equal to nh_only. */

enum { nh_normal,           /* conventional noteheads, with stems and beams */
       nh_cross,            /* X noteheads, with stems and beams */
       nh_harmonic,         /* diamond-shaped, with stems and beams */
       nh_none,             /* no noteheads, just stems and beams */
       nh_only,             /* conventional noteheads, no stems or beams */
       nh_direct            /* fancy 'w', no stems or beams */
};

/* System or heading block identification */

enum { sh_system, sh_heading };

/* Types for data in a layout vector */

enum { lv_barcount, lv_repeatcount, lv_repeatptr, lv_newpage };

/* Specific sheet sizes */

enum { sheet_unknown, sheet_A5, sheet_A4, sheet_A3, sheet_B5, sheet_letter };

/* Identifiers for each type of font. Any changes in this table must be kept in
step with the list of 2-letter font ids which is kept in FontIdStrings. The
running PostScript copy in ps_IdStrings must also be kept at the same size. */

enum { font_rm, font_it, font_bf, font_bi,
       font_sy, font_mu, font_mf, font_xx,
       font_tablen = font_xx + MaxExtraFont };

/* Small caps are identified by a pseudo-font in some places. */

#define font_sc 256

/* Give names to error numbers so they can be more easily tracked. */

enum { ERR0,  ERR1,  ERR2,  ERR3,  ERR4,  ERR5,  ERR6,  ERR7,  ERR8,  ERR9,
       ERR10, ERR11, ERR12, ERR13, ERR14, ERR15, ERR16, ERR17, ERR18, ERR19,
       ERR20, ERR21, ERR22, ERR23, ERR24, ERR25, ERR26, ERR27, ERR28, ERR29,
       ERR30, ERR31, ERR32, ERR33, ERR34, ERR35, ERR36, ERR37, ERR38, ERR39,
       ERR40, ERR41, ERR42, ERR43, ERR44, ERR45, ERR46, ERR47, ERR48, ERR49,
       ERR50, ERR51, ERR52, ERR53, ERR54, ERR55, ERR56, ERR57, ERR58, ERR59,
       ERR60, ERR61, ERR62, ERR63, ERR64, ERR65, ERR66, ERR67, ERR68, ERR69,
       ERR70, ERR71, ERR72, ERR73, ERR74, ERR75, ERR76, ERR77, ERR78, ERR79,
       ERR80, ERR81, ERR82, ERR83, ERR84, ERR85, ERR86, ERR87, ERR88, ERR89,
       ERR90, ERR91, ERR92, ERR93, ERR94, ERR95, ERR96, ERR97, ERR98, ERR99,
       ERR100,ERR101,ERR102,ERR103,ERR104,ERR105,ERR106,ERR107,ERR108,ERR109,
       ERR110,ERR111,ERR112,ERR113,ERR114,ERR115,ERR116,ERR117,ERR118,ERR119,
       ERR120,ERR121,ERR122,ERR123,ERR124,ERR125,ERR126,ERR127,ERR128,ERR129,
       ERR130,ERR131,ERR132,ERR133,ERR134,ERR135,ERR136,ERR137,ERR138,ERR139,
       ERR140,ERR141,ERR142,ERR143,ERR144,ERR145,ERR146,ERR147,ERR148,ERR149,
       ERR150,ERR151,ERR152,ERR153,ERR154,ERR155,ERR156 };


/*************************************************
*               Structure Definitions            *
*************************************************/

/* See further up for the structures "tree_node", "headstr", and "gaptextstr",
which are used in barhdr and so have to be defined before it is included. */


/* Structure for handling macros. We can't unfortunately have a variable length
vector at the end, as C doesn't support such things. */

typedef struct {
  int  argcount;       /* number of default arguments */
  uschar *text;        /* replacement text */
  uschar *args[1];     /* vector of pointers */
} macrostr;


/* Items in a kerning table, pointed to from a fontstr */

typedef struct kerntablestr {
  usint pair;
  int kwidth;
} kerntablestr;


/* Items in Unicode translation table, pointed to from a fontstr */

typedef struct utrtablestr {
  int unicode;
  int pscode;
} utrtablestr;


/* Font data */

typedef struct {
  uschar *psname;                 /* PostScript font name */
  int *widths;                    /* Pointer to basic width table */
  int *r2ladjusts;                /* Pointer to right-to-left adjusts */
  int *heights;                   /* Pointer to height table, if any */
  int kerncount;                  /* Size of kern table */
  int utrcount;                   /* Size of utr table */
  utrtablestr *utr;               /* Unicode translation for nonstd font */
  tree_node *high_tree;           /* Tree for data for high val stdenc chars */
  kerntablestr *kerns;            /* Pointer to kerning table */
  BOOL stdencoding;               /* True if std encoding */
  BOOL fixedpitch;                /* True if fixed pitch */
  BOOL hasfi;                     /* True if has "fi" */
  BOOL include;                   /* True if to include in output */
} fontstr;


/* Offsets for special text font sizes and matrices, which follow in the same
vector as sizes specified by the user. */

#define ff_offset_ts     (MaxFontSizes)
#define ff_offset_ulay   (ff_offset_ts+1)
#define ff_offset_olay   (ff_offset_ulay+1)
#define ff_offset_fbass  (ff_offset_olay+1)
#define ff_offset_init   (ff_offset_fbass+1)
#define SIZES_SIZE       (ff_offset_init+1)

/* Structure for overall font sizes at standard magnification, and
pointers to matrices for font stretching and shearing, where defined. */

typedef struct {
  int fontsize_music;
  int fontsize_grace;
  int fontsize_cue;
  int fontsize_cuegrace;
  int fontsize_clefs;
  int fontsize_barno;
  int fontsize_footnote;
  int fontsize_rehearse;
  int fontsize_triplet;
  int fontsize_repno;                 /* repeat bar number */
  int fontsize_restct;                /* long rest count */
  int fontsize_trill;
  int fontsize_vertacc;               /* vertical accidentals */
  int fontsize_text[SIZES_SIZE];      /* vector of sizes */

  /* These must be in the same order as the font sizes, and music must
  be first. */

  int *fontmatrix_music;
  int *fontmatrix_grace;
  int *fontmatrix_cue;
  int *fontmatrix_cuegrace;
  int *fontmatrix_clefs;
  int *fontmatrix_barno;
  int *fontmatrix_footnote;
  int *fontmatrix_rehearse;
  int *fontmatrix_triplet;
  int *fontmatrix_repno;
  int *fontmatrix_restct;
  int *fontmatrix_trill;
  int *fontmatrix_vertacc;
  int *fontmatrix_text[SIZES_SIZE];
} fontsizestr;


/* Data for spacing at the start of a line */

typedef struct {
  int clefspace;
  int keyspace;
  int timespace;
  int notespace;
} startlinestr;


/* One item in a chain of stave selections */

typedef struct stave_list {
  struct stave_list *next;
  int first;
  int last;
} stave_list;


/* One stave name text */

typedef struct snamestr {
  struct snamestr *next;
  struct snamestr *extra;     /* additional string(s); maybe different options */
  uschar *text;
  tree_node *drawing;
  drawitem  *args;            /* for drawing */
  uschar  flags;
  uschar  offset;
  uschar  linecount;
} snamestr;


/* One printtime item */

typedef struct ptimestr {
  struct ptimestr *next;
  int movt_number;          /* movement in which defined */
  int time;
  uschar *top;
  uschar *bot;
  uschar  offsettop;
  uschar  offsetbot;
} ptimestr;

/* One printkey item */

typedef struct pkeystr {
  struct pkeystr *next;
  int movt_number;          /* movement in which defined */
  int key;
  int clef;
  uschar *string;
  uschar *cstring;
} pkeystr;

/* One transposed key masquerade item */

typedef struct trkeystr {
  struct trkeystr *next;
  int oldkey;
  int newkey;
} trkeystr;

/* One KeyTranspose item */

typedef struct keytransposestr {
  struct keytransposestr *next;
  int oldkey;
  int newkeys[12];
  int letterchanges[12];
} keytransposestr;


/* Data pertaining to one stave */

typedef struct {
  bstr    **barindex;
  snamestr *stave_name;
  int       lastbar;
  int       toppitch;
  int       botpitch;
  int       totalpitch;
  short int notecount;
  CBOOL     omitempty;
  uschar    stavelines;
  uschar    barlinestyle;
} stavestr;


/* Layout of the items in the final position table for a bar */

typedef struct {
  int  moff;     /* musical offset of the position */
  int  xoff;     /* horizontal offset */
} posstr;


/* Layout of one item in a bar's positioning table while it is being worked on.
The stemup & stemdown flags are used as stated only at the beginning of
processing, when non-grace notes are the only things considered. For auxiliary
items, the stemup field is re-used to track which staves have the auxiliary
item. We should really use a union, but the notation is too messy! In the pos
routines which use this we cheat by defining a macro "posstaves" instead. */

typedef struct {
  int  moff;
  int  xoff;
  int  space;                        /* additional space required */
  usint stemup[STAVE_BITVEC_SIZE];   /* bitmap of staves where there is an */
                                     /*  actual stem up, aka "posstaves" */
  usint stemdown[STAVE_BITVEC_SIZE]; /* ditto for stem down */
  int  auxid;                        /* identification of auxiliary items */
                                     /*  (may be -ve) */
 } workposstr;


/* Layout of the entries in the vector kept for a movement's bars */

typedef struct {
  posstr *vector;     /* points to positioning vector */
  int  barnoX;        /* X offset for bar number */
  int  barnoY;        /* Y offset for bar number */
  short int count;    /* number of entries in the vector */
  short int multi;    /* multi-bar rest count */
  uschar posxRL;      /* offset for left repeat */
  uschar barnoforce;  /* force/unforce flag */
} barposstr;


/* Layout of structure for remembering things while measuring a line. Three
versions of this are kept: previous points to the version that was current
after accepting the previous bar; accepted points to the current structure
after accepting a bar; next points to the values that have changed as a result
of measuring the bar being checked. */

typedef struct {
  int   xposition;             /* total width of bars */
  int   startxposition;        /* position of lhs, after stave names */
  int   endbar;                /* end bar number */
  int   count;                 /* count of bars */
  int   notespacing[8];        /* notespacing values */
  usint notsuspend[STAVE_BITVEC_SIZE];  /* not suspended staves */
  snamestr **stavenames;       /* stave name vector */
  CBOOL endkey;                /* line ends with key signature */
  CBOOL endtime;               /* line ends with time signature */
} pagedatastr;


/* Structure for keeping data about a copy of stave 0 for another stave */

struct contstr;                /* Defined further down */

typedef struct zcopystr {
  struct zcopystr *next;
  struct contstr *cont;        /* Holds cont ptr for this copy */
  int  adjust;                 /* Overall adjustment for this stave */
  int  baradjust;              /* Adjustment for this bar */
  int  level;                  /* Used to hold actual level for printing */
  int  stavenumber;            /* Stave to overprint */
} zcopystr;


/* Data pertaining to a movement */

typedef struct {
  stavestr **stavetable;

  fontsizestr  *fontsizes;
  barposstr    *posvector;
  startlinestr *startline;
  zcopystr     *zcopy;

  stave_list *bracelist;
  stave_list *bracketlist;
  stave_list *joinlist;
  stave_list *joindottedlist;
  stave_list *thinbracketlist;

  headstr *footing;
  headstr *heading;
  headstr *lastfooting;
  headstr *pagefooting;
  headstr *pageheading;

  b_playchangestr *play_changes;

  uschar  *barnovector;
  uschar  *hyphenstring;
  uschar  *trillstring;
  uschar  *play_volume;

  uschar  *midi_channel;
  uschar  *midi_note;
  uschar  *midi_voice;
  uschar  *midi_volume;

  int   *accadjusts;
  int   *accspacing;
  int   *notespacing;
  int   *layout;
  int   *midi_start;
  int   *play_tempo_changes;
  int   *stavesizes;
  int   *stave_ensure;
  int   *stave_spacing;
  int   *stemswaplevel;

  int   barcount;
  int   barlinesize;
  int   barlinespace;
  int   barlinestyle;
  int   barno_interval;
  int   barno_level;
  int   barno_textflags;
  int   baroffset;
  int   beamdepth;
  int   beamflaglength;
  int   botmargin;
  int   bracestyle;
  int   breveledgerextra;
  int   caesurastyle;
  int   clefsize;
  int   clefstyle;
  int   dotspacefactor;
  int   endlinesluradjust;
  int   endlineslurstyle;
  int   endlinetieadjust;
  int   endlinetiestyle;
  int   extenderlevel;
  int   font_barnumber;
  int   font_longrest;
  int   font_rehearse;
  int   font_repeat;
  int   font_time;
  int   font_triplet;
  int   footnotesep;
  int   gracespacing[2];
  int   gracestyle;
  int   hflatstyle;
  int   hsharpstyle;
  int   hairpinlinewidth;
  int   hairpinwidth;
  int   hyphenthreshold;
  int   justify;
  int   key;
  int   keyspacing;
  int   laststave;
  int   ledger;
  int   leftmargin;
  int   linelength;
  int   maxbarcount;
  int   maxbeamslope1;
  int   maxbeamslope2;
  int   movt_opt;
  int   number;
  int   overlaydepth;
  int   play_tempo;
  int   rehearsalstyle;
  int   repeatstyle;
  int   shorten;
  int   smallcapsize;
  int   startbracketbar;
  int   stemswaptype;
  int   systemgap;
  int   time;
  int   timespacing;
  int   topmargin;
  int   totalnocount;
  int   transpose;
  int   tripletlinewidth;
  int   truelinelength;
  int   underlaydepth;
  int   underlaystyle;

  usint breakbarlines[STAVE_BITVEC_SIZE];
  usint staves[STAVE_BITVEC_SIZE];
  usint suspend[STAVE_BITVEC_SIZE];

  int   clefwidths[clef_count];
  int   tailadjusts[8];

  CBOOL beamendrests;
  CBOOL breverests;
  CBOOL check;
  CBOOL checkdoublebars;
  CBOOL codemultirests;
  CBOOL fullbarend;
  CBOOL startjoin;
  CBOOL keydoublebar;
  CBOOL keywarn;
  CBOOL rehearsallsleft;
  CBOOL showtime;
  CBOOL showtimebase;
  CBOOL tiesoverwarnings;
  CBOOL timewarn;
  CBOOL startnotime;
  CBOOL spreadunderlay;
  CBOOL underlayextenders;
  CBOOL unfinished;

  signed char playtranspose[MAX_STAVE+1];
} movtstr;

/* Layout of the data for an active line gap */

typedef struct gapstr {
  struct gapstr *next;
  int x;
  b_linegapstr *gap;
} gapstr;

/* Layout of the data for an active slur */

typedef struct slurstr {
  struct slurstr *next;
  b_slurstr *slur;
  gapstr *gaps;
  int moff;
  int x;
  int y;
  int maxy;
  int miny;
  int lastx;
  int lasty;
  int slopeleft;
  int sloperight;
  short int count;
  short int section;
} slurstr;

/* Layout of the data for an active hairpin */

typedef struct {
  b_hairpinstr *hairpin;
  int x;
  int maxy;
  int miny;
} hairpinstr;

/* Layout of data for an active nth time bar. There can be a chain of these
when, e.g. 1 & 2 are given for the same bar. It is wasteful of store, but this
is so rare it isn't worth bothering. */

typedef struct nbarstr {
  struct nbarstr *next;
  b_nbarstr *nbar;
  int x;
  int maxy;
  int miny;
} nbarstr;

/* Layout of data for a pending underlay hyphen string or extension.
Also used for overlay, with levels going from olay_offset. */

typedef struct ulaystr {
  struct ulaystr *next;
  int x;                       /* start position */
  int y;                       /* vertical level */
  uschar type;                 /* '=' or '-' */
  uschar level;                /* underlay level */
  uschar htype;                /* hyphen type index */
} ulaystr;

/* Layout of data for custom built "hyphen type" */

typedef struct htypestr {
  struct htypestr *next;
  uschar *string1;             /* main repeat string */
  uschar *string2;             /* line start string */
  uschar *string3;             /* final case string */
  int font;                    /* initial font */
  int adjust;                  /* vertical adjust */
  uschar size1;                /* size for first string */
  uschar size2;                /* size for second string */
} htypestr;

/* Layout of data saved when a beam extends over a bar line.
Longestnote is used when the split is over a line end. */

typedef struct {
  int  firstX;
  int  firstY;
  int  slope;
  int  count;
  int  Xcorrection;
  int  longestnote;
  BOOL splitOK;
  BOOL upflag;
}obeamstr;

/* Layout of one stave's continuation data held in a vector for use
at the start of each system, and while setting the stave. */

typedef struct {
  slurstr    *slurs;           /* chain of pending slurs */
  hairpinstr *hairpin;         /* pending hairpin */
  nbarstr    *nbar;            /* chain of pending nth time bars */
  b_tiestr   *tie;             /* pending tie */
  ulaystr    *ulay;            /* pending {und,ov}erlay hyphens or extension */
  obeamstr   *overbeam;        /* data for beam over bar line */
  int         tiex;            /* start position for tie */
  int         time;            /* time signature */
  uschar      noteheadstyle;   /* sic */
  uschar      flags;           /* see below */
  uschar      clef;            /* current clef */
  uschar      key;             /* current key signature */
} contstr;

#define cf_bowingabove   1
#define cf_notes         2     /* on/off switch */
#define cf_triplets      4     /* on/off switch */
#define cf_noteheads     8     /* on/off switch for noteheads only */
#define cf_rdrepeat     16     /* last bar ended with double repeat */

#define cf_default (cf_bowingabove|cf_notes|cf_triplets)


/* Layout of data in a system block structure. Up to and including the movement
pointer it must have the same layout as a headblock, because they are held in
the same chain. */

typedef struct sysblock {
  uschar      type;             /* indicates sysblock or headblock */
  uschar      flags;            /* see below */
  uschar      overrun;          /* overrun (whole points) */
  uschar      dummy2;
  struct sysblock *next;        /* next system or headblock */
  movtstr  *movt;               /* -> relevant movement */
  /********** The following are specific to sysblock **********/
  snamestr **stavenames;        /* -> pointers to name structures */
  contstr  *cont;               /* -> vector of contstrs */
  int      *stavespacing;       /* -> vector of stave spacings */
  int      *ulevel;             /* -> vector of underlay levels */
  int      *olevel;             /* -> vector of overlay levels */
  int       systemgap;          /* system gap value */
  int       systemdepth;        /* total of stavespacings */
  int       xjustify;           /* justify amount for whole system */
  int       barlinewidth;       /* stretched for this system */
  int       startxposition;     /* position after staff name text */
  int       joinxposition;      /* position for joining signs */
  int       keyxposition;       /* position for key signature */
  int       timexposition;      /* position for time signature */
  int       firstnoteposition;  /* sic */
  usint     notsuspend[STAVE_BITVEC_SIZE];
                                /* staves not suspended in this system */
  usint     showtimes[STAVE_BITVEC_SIZE];
                                /* staves which have starting time signatures */
  short int barstart;           /* starting bar number */
  short int barend;             /* ending bar number */
} sysblock;

/* Flag bits */

#define sysblock_warnkey   1    /* print additional key signature warning bar */
#define sysblock_warntime  2    /* ditto, time signature */
#define sysblock_warn      3    /* mask for either one of the above */
#define sysblock_stretch   4    /* flag set when stretched */
#define sysblock_noadvance 8    /* don't advance vertically */


/* Layout of data in a head block structure. Up to and including the movement
pointer, it must have the same layout as a sysblock, because they are held in
the same chain. We avoid using a union because the notation is so long and
clumsy. */

typedef struct {
  uschar    type;           /* indicates sysblock or headblock */
  CBOOL     pageheading;    /* indicates this is a page heading */
  uschar    dummy2;
  uschar    dummy3;
  sysblock *next;
  movtstr  *movt;
  /********** The following are specific to headblock **********/
  headstr  *headings;
} headblock;


/* Layout of a head of page block */

typedef struct pagestr {
  struct pagestr  *next;
  sysblock  *sysblocks;     /* -> chain of head+sysblocks */
  headblock *footing;       /* -> footing blocks */
  int number;               /* page number */
  int topspace;             /* space to insert at top of page */
  int spaceleft;            /* space left (used for justifying) */
  int overrun;              /* space required to fit another system on */
} pagestr;


/* Layout of entry in music font printing structure */

typedef struct mfstr {
  struct mfstr *next;
  int x;
  int y;
  usint ch;                 /* Holds up to 4 chars */
} mfstr;


/* Layout of data structure used for saving drawing operations until the
end of a stave - to ensure they are over everything else. Use a union
to handle the two different types. */

struct overdrawstr_graphic {
  int linewidth;
  int gray;
  int ystave;
  int count;
  int data[1];
};

struct overdrawstr_text {
  uschar *text;
  int fontsize;
  int boxring;
  int xx;
  int yy;
  int matrix[4];
};

typedef struct overdrawstr {
  struct overdrawstr *next;
  BOOL texttype;
  union {
    struct overdrawstr_graphic g;
    struct overdrawstr_text t;
  } d;
} overdrawstr;



/*************************************************
*                Global variables                *
*************************************************/

extern movtstr *format_movt;           /* Pointer to movement for formatting */
extern movtstr **movement;             /* Pointer to vector of pointers */
extern movtstr *curmovt;               /* Current movement */
extern pagestr *curpage;               /* Current page */
extern int      curstave;              /* Current stave number */

extern uschar *arg_from_name;          /* Name on command line */
extern uschar *arg_to_name;            /* Name on command line */

extern BOOL bar_use_draw;              /* Use direct drawing for bar lines */

extern uschar *copyright;

extern FILE *debug_file;
extern BOOL debugging;

extern int  draw_gap;                  /* +/- 1, for /a or /b gaps */
extern int  draw_lgx;                  /* Line gap x0 value for draw */
extern int  draw_lgy;                  /* Line gap y0 value for draw */
extern int  draw_nextvariable;         /* Next variable number */
extern int  draw_ox;                   /* Draw origin coordinates */
extern int  draw_oy;
extern tree_node *draw_tree;           /* Tree of draw routines */
extern tree_node *draw_variable_tree;  /* Tree of draw variables */
extern int  draw_thickness;            /* Line thickness */

extern int  error_count;               /* Count of errors in one file */
extern int  error_maximum;             /* Limit (raiseable for testing) */
extern int  error_ptr_correction;      /* For pointing within strings */
extern int  error_skip;                /* Skip option */

#ifdef SUPPORT_B2PF
extern b2pf_context **font_b2pf_contexts;  /* Table of B2PF context pointers */
extern uint32_t *font_b2pf_options;    /* Table of B2PF options */
#endif
extern int  font_count;                /* Count of defined fonts */
extern int  font_basecount;            /* Ditto, as read from file */
extern uschar *font_IdStrings[];       /* 2-uschar ID strings */
extern fontstr *font_List;             /* In-store list of fonts */
extern uschar *font_data_default;      /* Default font data directory */
extern uschar *font_data_extra;        /* Additional font data directory */
extern uschar *font_music_default;     /* Default music font directory */
extern uschar *font_music_extra;       /* Additional music font directory */
extern int  font_sinr;                 /* Sin of rotation angle */
extern int  font_cosr;                 /* Cos of rotation angle */
extern int  font_stringheight;         /* 2nd value from width function */
extern int  *font_table;               /* Table of font identities */

extern int  font_transform[];          /* For esoteric fonts - normally unit */
extern int  font_xstretch;             /* Amount to stretch each space by */

extern uschar init_midi_voice[];       /* Default midi voice structure */
extern movtstr init_movtstr;           /* Initializing movement structure */
extern int  init_notespacing[];        /* Initial notespacing value */
extern int  init_stavesizes[];         /* Initial stave sizes table */
extern zcopystr init_zcopy;            /* Default stave zero copy structure */
extern FILE *input_file;               /* The current input file */

extern uschar length_table[];          /* Table of item lengths */
extern int  longrest_barwidths[];      /* Fixed widths for longrest bars */
extern int  longrest_widths[];         /* Widths of longrest symbols */

extern usint main_bit[];               /* Table of bits in a word */
extern uschar *main_caesurastrings[];  /* For printing caesuras */
extern int  main_clefoffset[];         /* Offsets in tables for clefs */
extern int  main_cleftypes[];          /* Types of shape indicators for next */
extern uschar *main_filename;          /* Name of current file */
extern int  main_firstpage;            /* Number of first page */
extern int  main_flatorder[];          /* Key sig table */
extern uschar *main_format;            /* User-selected format */
extern BOOL main_format_tested;        /* Format has been tested */
extern htypestr *main_htypes;          /* Chain of hyphen types */
extern BOOL main_initialized;          /* True when initialized */
extern BOOL main_kerning;              /* Kerning flag */
extern int  main_keysigtable[];        /* Table of sharps and flats */
extern keytransposestr *main_keytranspose; /* List of explicit transpositions */
extern int  main_lastmovement;         /* Number of last movement */
extern int  main_lastpage;             /* Number of last page */
extern int  main_magnification;        /* Overall magnification */
extern int  main_max_bars;             /* Max bars per staff */
extern int  main_max_movements;        /* Maximum number of movements */
extern int  main_maxvertjustify;       /* Max vertical justification */
extern uschar *main_musicchoice;       /* Music file named in Choices */
extern int  main_notenum;              /* Multiplies length */
extern int  main_noteden;              /* Divides length */
extern int  main_notespacing[];        /* Start of movement values */
extern pagestr *main_pageanchor;       /* Anchor of page structure */
extern int  main_pageinc;              /* Page increments */
extern int  main_pagelength;           /* Virtual page length */
extern pkeystr *main_printkey;         /* Chain of printkey structs */
extern ptimestr *main_printtime;       /* Chain of printtime structs */
extern headstr *main_pssetup;          /* PostScript set-up "headings" */
extern int  main_rc;                   /* The final return code */
extern BOOL main_righttoleft;          /* As it says */
extern int  main_sharporder[];         /* Key sig order table */
extern int  main_sheetheight;          /* Height of paper */
extern int  main_sheetwidth;           /* Width of paper */
extern BOOL main_shownlogo;            /* FALSE if need to show logo on error */
extern int  main_stavemagn;            /* Magnification for current stave */
extern usint main_staves[STAVE_BITVEC_SIZE]; /* External stave selection */
extern int  main_storetotal;           /* Total store used */
extern int  main_storestaves;          /* Store used for staves */
extern int  main_stretchrespacethresh; /* Threshold for re-spacing */
extern int  main_stretchthreshnum;     /* Stretching threshold */
extern int  main_stretchthreshden;
extern int  main_totalbars;            /* Total number of bars */
extern int  main_tracepos;             /* Debugging option */
extern int  main_transpose;            /* External transpose value */
extern BOOL main_transposedaccforce;   /* TRUE => retain accs when transposed */
extern trkeystr *main_transposedkeys;  /* Transposed keys masquerades */
extern int  main_truepagelength;       /* Actual page length */
extern uschar main_xkeys[MAX_XKEYS][10]; /* Custom key signatures */

extern uschar *midi_filename;          /* name of MIDI file */
extern BOOL    midi_for_notes_off;     /* If TRUE, do MIDI even if [notes off] */
extern uschar *midi_perc;              /* File name with midi perc */
extern uschar *midi_percnames;         /* Percussion name => "pitch" */
extern uschar *midi_voices;            /* File name with midi voices */
extern uschar *midi_voicenames;        /* Voice name => voice number */

extern int  music_xmovement[];         /* Table of x movement-chars */
extern int  music_ymovement[];         /* Ditto y */

extern BOOL opt_landscape;             /* User-settable options */
extern BOOL opt_oldbeambreak;
extern BOOL opt_oldrestlevel;
extern BOOL opt_oldstemlength;
extern BOOL opt_print_postscript;
extern int  opt_sheetsize;
extern int  opt_stretchrule;

extern int  play_endbar;
extern int  play_movt_number;
extern BOOL play_repeats;
extern int  play_startbar;

extern stave_list *print_curlist;      /* Printing selection list */
extern int  print_curnumber;           /* Printing page number */
extern int  print_gutter;              /* Gutter adjustment */
extern int  print_imposition;          /* Imposition option */
extern int  print_lastpage;            /* Logical last page number */
extern int  print_image_xadjust;       /* Image adjustment values */
extern int  print_image_yadjust;
extern int  print_image_sxadjust;      /* ... for sideways paper */
extern int  print_image_syadjust;
extern int  print_magnification;       /* Scaling value */
extern int  print_pagefeed;            /* Page feed type */
extern int  print_pageorigin;          /* Page origin type */
extern BOOL print_pamphlet;            /* Printing options */
extern BOOL print_reverse;
extern BOOL print_side1;
extern BOOL print_side2;
extern uschar *ps_header;              /* Name of PostScript header file */

extern BOOL reading_input;             /* TRUE while reading */

extern stavestr *stavehead;            /* Points to current stave structure */
extern stavestr **stavetable;          /* Points to pointers to stave struct */

extern int  stave_bottoms[];           /* Levels of top/bottom lines of staves */
extern int  stave_tops[];
extern int  stave_use_draw;            /* Use direct drawing for staves */
extern BOOL stave_use_widechars;       /* Use 100-pt chars for staves */

extern const int     utf8_table1[];    /* Various tables for UTF-8 processing */
extern const int     utf8_table2[];
extern const int     utf8_table3[];
extern const uschar  utf8_table4[];

extern int  string_font;               /* Final font after measuring a string */
extern BOOL verify;                    /* The -v option */
extern int  version_fixed;             /* Identity number in binary */
extern uschar version_string[];        /* Identity of program version */




/*************************************************
*                 Global procedures              *
*************************************************/

extern void debug_printf(const char *, ...);
extern void debug_showbar(int, int, int);

#ifdef Debug
extern void  debug_showbarpos(int, int);
extern void  debug_showglobals(void);
extern void  debug_showmovement(int);
extern void  debug_showpage(int);
extern void  debug_showstave(int, int);
#endif

extern uschar *define_find(uschar *);

extern void  error_moan(int, ...);

extern FILE *font_finddata(uschar *, const char *, uschar *, uschar *,
               uschar *, BOOL);
extern int   font_fontword(BOOL);
extern void  font_init(void);
extern void  font_loadtables(int);
extern void  font_reset(void);
extern void  font_rotate(int);
extern int   font_search(uschar *);
extern int   font_stringwidth(uschar *, int, int);
extern int   font_utranslate(int, fontstr *);

extern int   format_sprintf(uschar *, const char *, ...);      /* 2nd is format */
extern int   format_vsprintf(uschar *, const char *, va_list); /* ditto */

extern void  info_printf(const char *, ...);
extern int   init_command(int, char **, char **, const char *);

extern void  main_tidyup(void);

extern void  midi_write(void);

extern void       misc_commoncont(bstr *);
extern contstr   *misc_copycontstr(contstr *, int, BOOL);
extern void       misc_drawslur(slurstr *, int, int, BOOL);
extern void       misc_freecontstr(contstr *, int);
extern slurstr   *misc_getendslur(bstr *);
extern int        misc_keywidth(int, int);
extern b_notestr *misc_nextnote(b_notestr *, int *);
extern int        misc_ord2utf8(int, uschar *);
extern slurstr   *misc_setstartslur(bstr *);
extern int        misc_timewidth(int);
extern int        misc_ybound(int, b_tiestr *, BOOL, BOOL);

extern void  paginate_go(void);
extern BOOL  print_nextpage(pagestr **, pagestr **);
extern void  print_setup_pagelist(BOOL);
extern void  ps_go(void);

extern void  read_start(void);
extern void  read_go(void);
extern void  read_midi_translation(uschar **, uschar *);

extern void *store_copy(void *);
extern uschar *store_copystring(uschar *);
extern void  store_debug_print(void);
extern void  store_debug_print(void);
extern void  store_free(void *);
extern void *store_get(usint);
extern void *store_getitem(int);
extern void *store_nextitem(void);
extern void *store_Xget(int);

extern uschar *string_check(uschar *);
extern uschar *string_escape(uschar *, uschar *, int *, int *);
extern uschar *string_read(void);
extern void    string_stavestring(BOOL);
extern int     string_width(uschar *, int, int);

extern void  sys_relativize(uschar *, int);

extern int   transpose_key(int, int);
extern int   transpose_note(int, int *, int *, int, BOOL, BOOL, BOOL, int);

extern BOOL  Tree_InsertNode(tree_node **, tree_node *);
extern tree_node *Tree_Search(tree_node *, uschar *);

extern void  version_init(void);

/* End of pmwhdr.h */
