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

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

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


/* This file contains initializing code, including the main program, which is
the entry point to PMW.


This comment is historical, left here for nostalgia purposes only:

------------------------------------------------------------------------------
PMW can be run in an windowing environment, or as a command-line program.
The windowing environments are of course system-specific, but have the
characteristic that they are event-driven. Thus in such an environment
we hand over control to a system routine, and only get it back (if at all)
when the program is finishing.

For the moment, we are thinking only of the RISC OS environment, but
writing as flexibly as possible, so that future ports are easier.
------------------------------------------------------------------------------

The future has arrived. This port of PMW for Unix-like systems runs only as a
single command, processing a single input file (though that may include
other files). Much of the old apparatus for the previous windowing version has
been tidied away, but there are still a few quirks in the way the code works
that hark back to the original, event-driven implementation. */


#include "rdargs.h"
#include "pmwhdr.h"
#include "outhdr.h"


/* Keywords for the command line. If you increase the number of keys, make sure
that the keyoffset field in rdargs.c is big enough. */

static const char *arg_pattern =
  ","
  "a4ona3/s,"
  "a4sideways/s,"
  "a5ona4/s,"
  "c/k/n,"
  "debug/s,"
  "dbl=drawbarlines/s,"
  "dsl=drawstavelines=drawstafflines/n=3,"
  "dsb/k,"
  "dtp/k/n,"
  "duplex/s,"
  "em=errormaximum/n,"
  "eps/s,"
  "F/k,"
  "f/k,"
  "H/k,"
  "-help=help/s,"
  "incPMWfont=incpmwfont=ipf=includefont/s,"
  "MF/k,"
  "MP/k,"
  "MV/k,"
  "manualfeed/s,"
  "midi/k,"
  "mb=midibars/k,"
  "mm=midimovement/k/n,"
  "norc=nopmwrc/s,"
  "nr=norepeats=norepeat/s,"
  "nw=nowidechars/s,"
  "o/k,"
  "p/k,"
  "pamphlet/s,"
  "printadjust/k/2,"
  "printgutter/k,"
  "printscale/k,"
  "printside/k/n,"
  "reverse/s,"
  "s/k,"
  "t/k/n,"
  "tumble/s,"
  "-version=V/s,"
  "v/s";

/* Offsets for command line keys */

enum {
  arg_aa_input,    /* The only unkeyed possibility */
  arg_a4ona3,
  arg_a4sideways,
  arg_a5ona4,
  arg_c,
  arg_debug,
  arg_drawbarlines,
  arg_drawstavelines,
  arg_dsb,
  arg_dtp,
  arg_duplex,
  arg_em,
  arg_eps,
  arg_F,
  arg_f,
  arg_H,
  arg_help,
  arg_incPMWfont,
  arg_MF,
  arg_MP,
  arg_MV,
  arg_manualfeed,
  arg_midi,
  arg_midibars,
  arg_midimovement,
  arg_norc,
  arg_norepeats,
  arg_nowidechars,
  arg_o,
  arg_p,
  arg_pamphlet,
  arg_printadjustx,
  arg_printadjusty,
  arg_printgutter,
  arg_printscale,
  arg_printside,
  arg_reverse,
  arg_s,
  arg_t,
  arg_tumble,
  arg_V,
  arg_v
};


/* Parameters for debugging with -dsb option */

static int dsb_bar = -1;
static int dsb_movement = -1;
static int dsb_stave = -1;

/* Vector for modified command line options */

static char **newargv;


/*************************************************
*          Given help on command syntax          *
*************************************************/

static void
givehelp(void)
{
printf("\nPMW version %s\n%s\n", version_string, copyright);

printf("\n            OPTIONS\n\n");
printf("-a4ona3               print A4 images 2-up on A3\n");
printf("-a5ona4               print A5 images 2-up on A4\n");
printf("-a4sideways           assume A4 paper fed sideways\n");
printf("-c <number>           set number of copies\n");
printf("-debug                write debugging info to stderr\n");
printf("-dbl                  synonym for -drawbarlines\n");
printf("-drawbarlines         don't use characters for bar lines\n");
printf("-drawstavelines [<n>] don't use characters for stave lines\n");
printf("-dsb <m>,<s>,<b>      write debugging bar data (movement, stave, bar) \n");
printf("-dsl [<n>]            synonym for -drawstavelines\n");
printf("-dtp <bar>            write debugging position data (-1 for all bars)\n");
printf("-duplex               set duplex printing in the PostScript\n");
printf("-em <n>               synonym for -errormaximum\n");
printf("-eps                  output encapsulated PostScript\n");
printf("-errormaximum <n>     set maximum number of errors (for testing)\n");
printf("-F <directory-list>   specify fontmetrics and/or .utr directories\n");
printf("-f <name>             specify format name\n");
printf("-H <file>             specify PostScript header file\n");
printf("-help                 output this information\n");
printf("-incPMWfont           include PMW font in the output\n");
printf("-ipf                  synonym for -incPMWfont\n");
printf("-MF <directory-list>  specify PostScript music fonts directories\n");
printf("-MP <file>            specify MIDIperc file\n");
printf("-MV <file>            specify MIDIvoices file\n");
printf("-manualfeed           set manualfeed in the PostScript\n");
printf("-mb <range>           synonym for -midibars\n");
printf("-midi <file>          specify MIDI output file\n");
printf("-midibars <range>     limit MIDI output to given bar range\n");
printf("-midimovement <n>     specifies movement for MIDI output\n");
printf("-mm <n>               synonym for -midimovement\n");
#ifndef NO_PMWRC
printf("-norc or -nopmwrc     don't read .pmwrc (must be first option)\n");
#endif
printf("-norepeats            do not play repeats in MIDI output\n");
printf("-nowidechars          don't use 100-point stave chars\n");
printf("-nr                   synonym for -norepeats\n");
printf("-nw                   synonym for -nowidechars\n");
printf("-o <file>             specify output file ('-' for stdout)\n");
printf("-p <list>             select pages\n");
printf("-pamphlet             print pages in pamphlet order\n");
printf("-printadjust <x> <y>  move on page by (x,y)\n");
printf("-printgutter <x>      move recto/verso pages by x/-x\n");
printf("-printscale <n>       scale the image by n\n");
printf("-printside <n>        print only odd or even sides\n");
printf("-reverse              output pages in reverse order\n");
printf("-s <list>             select staves\n");
printf("-t <number>           set transposition\n");
printf("-tumble               set tumble for duplex printing\n");
printf("-V                    output PMW version number\n");
printf("-v                    output verification information\n");

printf("\nDefault output is <input>.ps when a file name is given.\n");
printf("Default output is stdout if no file name is given.\n");

printf("\n          EXAMPLES\n\n");
printf("pmw myscore\n");
printf("pmw -s 1,2-4 -p 3,6-10,11 -f small -c 2 k491.pmw\n");
printf("pmw -pamphlet -a5ona4 scorefile\n");
printf("pmw -s 1 -midi zz.mid -mm 2 -mb 10-20 sonata\n");
}



/*************************************************
*           Print routine for info display       *
*************************************************/

/* This could just be replaced by fprintf() to stderr nowadays, but we keep the
separate function just in case in the future we want do so something else with
all this output. The function is global because it is also called from
setdraw.c to show the contents of the draw stack.

Arguments:
  format      a format
  ...         data for the format

Returns:      nothing
*/

void
info_printf(const char *format, ...)
{
uschar buff[256];
va_list ap;
va_start(ap, format);
format_vsprintf(buff, format, ap);
fprintf(stderr, "%s", CS buff);
va_end(ap);
}



/*************************************************
*        Display information about music         *
*************************************************/

/* This function is called after pagination if the -v option is present.

Arguments:  none
Returns:    nothing
*/

static void
display_info(void)
{
pagestr *p = main_pageanchor;
int movt;
int laststave = -1;
int toppitch[MAX_STAVE+1];
int botpitch[MAX_STAVE+1];
int totalpitch[MAX_STAVE+1];
int notecount[MAX_STAVE+1];

info_printf("Data store used = ");
if (main_storetotal < 10000) info_printf("%d", main_storetotal);
  else info_printf("%dK", main_storetotal/1024);
info_printf(" (stave data ");
if (main_storestaves < 10000) info_printf("%d", main_storestaves);
  else info_printf("%dK", main_storestaves/1024);
info_printf(")\n");

/* Display information about the staves in each movement */

for (movt = 1; movt <= main_lastmovement; movt++)
  {
  int stave;
  movtstr *m = movement[movt];

  info_printf("\nMOVEMENT %d\n\n", movt);

  for (stave = 0; stave <= m->laststave; stave++)
    {
    stavestr *s = (m->stavetable)[stave];
    if (s == NULL) continue;               /* skips stave 0 if not there */

    info_printf("Stave %2d: ", stave);

    if (m->totalnocount == 0)
      info_printf("%d bar%s", s->lastbar, (s->lastbar == 1)? "":"s");
    else info_printf("%d(+%d) bars",
      s->lastbar - m->totalnocount, m->totalnocount);

    if (stave > laststave)
      {
      laststave = stave;
      toppitch[stave] = -1;
      botpitch[stave] = 9999;
      notecount[stave] = totalpitch[stave] = 0;
      }

    if (s->notecount > 0)
      {
      info_printf(";%s range  %P to %P average %P",
        (s->lastbar == 1)? " ":"",
          s->botpitch, s->toppitch, s->totalpitch/s->notecount);

      if (s->toppitch > toppitch[stave]) toppitch[stave] = s->toppitch;
      if (s->botpitch < botpitch[stave]) botpitch[stave] = s->botpitch;
      totalpitch[stave] += s->totalpitch;
      notecount[stave] += s->notecount;
      }

    info_printf("\n");
    }
  }


/* If there is more than one movement, display overall information for each
stave. */

if (main_lastmovement > 1)
  {
  int stave;
  info_printf("\nOVERALL\n\n");
  for (stave = 1; stave <= laststave; stave++)
    {
    info_printf("Stave %2d: ", stave);
    if (notecount[stave] > 0)
      info_printf("range  %P to %P average %P",
        botpitch[stave], toppitch[stave], totalpitch[stave]/notecount[stave]);
    info_printf("\n");
    }
  }


/* Now display information about the page layout */

if (p != NULL) info_printf("\nPAGE LAYOUT\n\n");

while (p != NULL)
  {
  int count = 14;
  sysblock *s = p->sysblocks;
  info_printf("Page %d bars: ", p->number);

  while (s != NULL)
    {
    if (s->type == sh_system)
      {
      format_movt = s->movt;
      if (count > 65)
        {
        info_printf("\n ");
        count = 1;
        }
      info_printf("%b-%b%s ", s->barstart, s->barend,
        (s->flags & sysblock_stretch)? "":"*");
      count += 6;
      if (s->overrun < 30)
        {
        info_printf("(%d) ", s->overrun);
        count += 5;
        }
      }
    s = s->next;
    }

  info_printf("\n  Space left on page = %f", p->spaceleft);
  if (p->overrun > 0 && p->overrun < 100000)
    info_printf(" Overrun = %f", p->overrun);
  info_printf("\n");

  p = p->next;
  }
}



/*************************************************
*         Convert string to stave map            *
*************************************************/

/* The turns strings like "1,3,4-6,10" into a bitmap.
For some
reason gcc gives a weird warning if ss is used directly with strtol, even with
the right casts. That's why I use another variable of type char *.

Arguments:
  ss         the string
  endptr     where to return a pointer to the char after the last used
  map        pointer to bitmap, held as unsigned ints

Returns:     nothing
*/

static void
init_strtomap(uschar *ss, uschar **endptr, usint *map)
{
long int i;
char *sss = (char *)ss;
*endptr = ss;
mac_initstave(map, 0);
while (isdigit(*sss))
  {
  long int s = strtol(sss, &sss, 0);
  long int t = s;
  if (*sss == '-')
    {
    sss++;
    t = strtol(sss, &sss, 0);
    }
  if (t < s || t > MAX_STAVE) return;   /* Not reached end will give error */
  for (i = s; i <= t; i++) mac_setstave(map, i);
  while (*sss == ',' || *sss == ' ') sss++;
  }
*endptr = US sss;
}



/*************************************************
*             Decode command line                *
*************************************************/

/* -V and -help act immediately; otherwise the values from the command line
options are place in appropriate global variables.

Arguments:
  argc        the (possibly modified) command line argc
  argv        the (possibly modified) command line argv

Returns:      nothing
*/

static void
decode_command(int argc, char **argv)
{
arg_result results[80];
int rc = rdargs(argc, argv, arg_pattern, results);

if (rc != 0)
  error_moan(ERR0, results[0].text, results[1].text);  /* Hard */

/* -norc is invalid here; give an explanation. */

if (results[arg_norc].number != 0) error_moan(ERR153);

/* Deal with -V */

if (results[arg_V].number != 0)
  {
  printf("PMW version %s\n%s\n", version_string, copyright);
  exit(EXIT_SUCCESS);
  }

/* Deal with -help */

if (results[arg_help].number != 0)
  {
  givehelp();
  exit(EXIT_SUCCESS);
  }

/* Deal with verifying and debugging */

if (results[arg_v].number != 0) verify = TRUE;

if (results[arg_debug].number != 0)
  {
  debug_file = stderr;
  debugging = TRUE;
  debug_printf("PMW run started\n");
  }

if (results[arg_dsb].text != NULL)
  {
  if (strspn(results[arg_dsb].text, "0123456789,") !=
      strlen(results[arg_dsb].text)) error_moan(ERR77);   /* Hard */
  switch (sscanf(results[arg_dsb].text, "%d,%d,%d", &dsb_movement,
          &dsb_stave, &dsb_bar))
    {
    case 1:                           /* One value is a bar number */
    dsb_bar = dsb_movement;
    dsb_movement = dsb_stave = 1;
    break;

    case 2:                           /* Two values are stave, bar */
    dsb_bar = dsb_stave;
    dsb_stave = dsb_movement;
    dsb_movement = 1;
    break;

    case 3:                           /* Three values are movt, stave, bar */
    break;

    default:
    error_moan(ERR77);   /* Hard */
    break;
    }
  debug_file = stderr;
  }

if (results[arg_dtp].presence != arg_present_not)
  {
  debug_file = stderr;
  main_tracepos = results[arg_dtp].number;
  }

/* Deal with -from and -o */

if (results[arg_aa_input].text != NULL)
  arg_from_name = US results[arg_aa_input].text;

if (results[arg_o].text != NULL)
  arg_to_name = US results[arg_o].text;

/* Deal with overriding music fonts, fontmetrics, and psheader, MIDIperc, and
MIDIvoices files */

if (results[arg_F].text != NULL)
  font_data_extra = US results[arg_F].text;

if (results[arg_H].text != NULL)
  ps_header = US results[arg_H].text;

if (results[arg_MF].text != NULL)
  font_music_extra = US results[arg_MF].text;

if (results[arg_MP].text != NULL)
  midi_perc = US results[arg_MP].text;

if (results[arg_MV].text != NULL)
  midi_voices = US results[arg_MV].text;

/* Deal with MIDI output */

if (results[arg_midi].text != NULL)
  midi_filename = US results[arg_midi].text;

if (results[arg_midibars].text != NULL)
  {
  uschar *endptr;
  play_startbar = Ustrtoul(results[arg_midibars].text, &endptr, 10);
  if (*endptr == 0) play_endbar = play_startbar; else
    {
    if (*endptr++ != '-') error_moan(ERR123);     /* Hard error */
    play_endbar = Ustrtoul(endptr, &endptr, 10);
    if (*endptr != 0) error_moan(ERR123);         /* Hard error */
    }
  }

if (results[arg_midimovement].presence != arg_present_not)
  play_movt_number = results[arg_midimovement].number;

/* Error limit is adjustable, mainly for testing */

if (results[arg_em].presence != arg_present_not)
  error_maximum = results[arg_em].number;

/* Some BOOL options */

if (results[arg_norepeats].number != 0) play_repeats = FALSE;
if (results[arg_nowidechars].number != 0) stave_use_widechars = FALSE;
if (results[arg_drawbarlines].number != 0) bar_use_draw = TRUE;

/* Draw stave lines instead of using font characters: the thickness can
optionally be altered. */

if (results[arg_drawstavelines].presence != arg_present_not)
  stave_use_draw = results[arg_drawstavelines].number;

/* Deal with stave selection */

if (results[arg_s].text != NULL)
  {
  uschar *endptr;
  init_strtomap(US results[arg_s].text, &endptr, main_staves);
  mac_setstave(main_staves, 0);
  if (*endptr != 0) error_moan(ERR74);  /* Hard error */
  }

/* Deal with page selection */

if (results[arg_p].text != NULL)
  {
  uschar *s = US results[arg_p].text;
  stave_list *p;
  stave_list **pp = &output_pagelist;

  while (*s)
    {
    int first, last, n;
    int count = sscanf(CS s, "%d%n-%d%n", &first, &n, &last, &n);
    if (count == 0) error_moan(ERR75); else   /* Hard error */
      {
      p = malloc(sizeof(stave_list));
      p->first = first;
      if (count == 1) p->last = first; else
        {
        if (first > last) error_moan(ERR76);  /* Hard error */
          else p->last = last;
        }
      p->next = NULL;
      *pp = p;
      pp = &(p->next);
      }
    s += n;
    if (*s == ',') s++;
    }
  }

/* Deal with transposition */

if (results[arg_t].presence != arg_present_not)
  {
  main_transpose = results[arg_t].number;
  if (abs(main_transpose) > max_transpose)
    error_moan(ERR139, "T", main_transpose, max_transpose);  /* Hard error */
  }

/* Deal with format */

if (results[arg_f].text != NULL)
  {
  int i;
  uschar *f = US results[arg_f].text;
  main_format = malloc(sizeof(f) + 1);
  for (i = 0; i <= Ustrlen(f); i++) main_format[i] = tolower(f[i]);
  }

/* Deal with copies */

if (results[arg_c].presence != arg_present_not)
  output_copies = results[arg_c].number;

/* Deal with a number of printing configuration options */

if (results[arg_reverse].number != 0) print_reverse = TRUE;
if (results[arg_a4sideways].number != 0) print_pagefeed = pc_a4sideways;
if (results[arg_a4ona3].number != 0) print_imposition = pc_a4ona3;
if (results[arg_a5ona4].number != 0) print_imposition = pc_a5ona4;

if (results[arg_incPMWfont].number != 0) output_incPMWfont = TRUE;
if (results[arg_manualfeed].number != 0) output_manualfeed = TRUE;
if (results[arg_duplex].number != 0) output_duplex = TRUE;
if (results[arg_tumble].number != 0) output_tumble = TRUE;

if (results[arg_pamphlet].number != 0) print_pamphlet = TRUE;
if (results[arg_eps].number != 0) print_imposition = pc_EPS;

if (results[arg_printadjustx].text != NULL)
  {
  float d;
  sscanf(results[arg_printadjustx].text, "%g", &d);
  print_image_xadjust = (int)(1000.0 * d);
  }

if (results[arg_printadjusty].text != NULL)
  {
  float d;
  sscanf(results[arg_printadjusty].text, "%g", &d);
  print_image_yadjust = (int)(1000.0 * d);
  }

if (results[arg_printgutter].text != NULL)
  {
  float d;
  sscanf(results[arg_printgutter].text, "%g", &d);
  print_gutter = (int)(1000.0 * d);
  }

if (results[arg_printscale].text != NULL)
  {
  float d;
  sscanf(results[arg_printscale].text, "%g", &d);
  print_magnification = (int)(1000.0 * d);
  if (print_magnification == 0) error_moan(ERR11);  /* Hard */
  }

if (results[arg_printside].presence != arg_present_not)
  {
  int n = results[arg_printside].number;
  if (n == 1) print_side2 = FALSE;
    else if (n == 2) print_side1 = FALSE;
      else error_moan(ERR66);  /* Hard */
  }
}



/*************************************************
*              Exit function                     *
*************************************************/

/* Used to free various chunks of memory. */

static void
clean_up(void)
{
#ifdef SUPPORT_B2PF
int i;
for (i = 0; i < font_tablen; i++)
  {
  if (font_b2pf_contexts[i] != NULL) b2pf_context_free(font_b2pf_contexts[i]);
  }
#endif
free(newargv);
}


/*************************************************
*                Entry Point                     *
*************************************************/

int
main(int argc, char **argv)
{
int i, newargc;
uschar to_buffer[256];
verify = FALSE;
ps_file = stdout;

font_data_default = US FONTMETRICS;
font_data_extra = NULL;
font_music_default = US FONTDIR;
font_music_extra = NULL;
ps_header = US PSHEADER;
midi_voices = US MIDIVOICES;
midi_perc = US MIDIPERC;

(void)atexit(clean_up);
version_init();

font_List = malloc(MAX_FONTS * sizeof(fontstr));
font_table = malloc(font_tablen * sizeof(int));

#ifdef SUPPORT_B2PF
font_b2pf_contexts = malloc(font_tablen * sizeof(b2pf_context *));
font_b2pf_options = malloc(font_tablen * sizeof(uint32_t));
for (i = 0; i < font_tablen; i++)
  {
  font_b2pf_contexts[i] = NULL;
  font_b2pf_options[i] = 0;
  }
#endif

beam_stemadjusts = malloc(MAX_BEAMSIZE);
movement = malloc((main_max_movements+1) * sizeof(movtstr *));

/* Decode the (possibly modified) command line. */

newargv = malloc(100 * sizeof(char *));
newargc = init_command(argc, argv, newargv, arg_pattern);
decode_command(newargc, newargv);
if (verify)
  {
  fprintf(stderr, "PMW version %s\n", version_string);
  main_shownlogo = TRUE;
  }

/* Set up default fonts */

font_init();

/* Initialize MIDI data */

read_midi_translation(&midi_voicenames, midi_voices);
read_midi_translation(&midi_percnames, midi_perc);

/* Initialization done */

main_initialized = TRUE;

/* Sort out the input file, and possibly the name of the output file. If no
input file is supplied, read stdin. Output is to stdout (default) unless
overridden by -o (arg_to_name will be set). */

if (arg_from_name == NULL)
  {
  input_file = stdin;
  }
else
  {
  main_filename = arg_from_name;
  input_file = Ufopen(main_filename, "r");
  if (input_file == NULL)
    error_moan(ERR4, main_filename, strerror(errno));  /* Hard error */

  if (arg_to_name == NULL)
    {
    uschar *p;
    arg_to_name = to_buffer;
    Ustrcpy(arg_to_name, arg_from_name);
    p = arg_to_name + Ustrlen(arg_to_name);
    while (p > arg_to_name && p[-1] != '.' && p[-1] != '/') p--;
    if (p > arg_to_name && p[-1] == '.') p[-1] = 0;
    Ustrcat(arg_to_name, ".ps");
    }
  }

/* Read the file */

if (verify) fprintf(stderr, "Reading ...\n");
read_start();
read_go();
if (main_rc > rc_warning) return main_rc;

/* Output debugging if requested */

if (dsb_movement > 0) debug_showbar(dsb_movement, dsb_stave, dsb_bar);

/* Do the typesetting */

if (verify) fprintf(stderr, "Paginating ...\n");
paginate_go();
if (main_rc > rc_warning) return main_rc;

/* Show pagination information if verifying */

if (verify) display_info();

/* If a file name other than "-" is set for the output, open it. Otherwise
we'll be writing to stdout. */

if (arg_to_name != NULL && Ustrcmp(arg_to_name, "-") != 0)
  {
  if (verify)
    fprintf(stderr, "\nWriting PostScript file \"%s\" ...\n", arg_to_name);
  ps_file = Ufopen(arg_to_name, "w");
  if (ps_file == NULL)
    error_moan(ERR4, arg_to_name, strerror(errno));  /* Hard error */
  }
else if (verify) fprintf(stderr, "\nWriting Postscript to stdout ...\n");

/* Set up for printing, and go for it */

print_lastpage = main_lastpage;
if (print_pamphlet) print_lastpage = (print_lastpage + 3) & (-4);

/* This diagram shows the computed values and the positions where the origin
can go in each case. In practice we take the upper value where there are two
possibilities.

 ------------ Sideways -------------   |   ------------ Upright -----------
 ----- 1-up -----   ----- 2-up -----   |   ---- 1-up ----    ---- 2-up ----
  Port     Land      Port     Land     |    Port     Land     Port     Land
 x------  -------   -------  ---x---   |   -----    x----    x----    -----
 |  0  |  |  4  |   |  2  |  |  6  |   |   |   |    |   |    |   |    |   |
 ------x  x------   x------  ---x---   |   | 1 |    | 5 |    | 3 |    x 7 |
                                       |   |   |    |   |    |   |    |   |
                                       |   x----    -----    ----x    -----
*/

print_pageorigin =
  ((print_pagefeed == pc_a4sideways)? 0 : 1) +
  ((print_imposition == -1)? 0 : 2) +
  (opt_landscape? 4 : 0);

ps_go();
if (ps_file != stdout) fclose(ps_file);

/* Output warning if coupled staves were not spaced by a multiple of 4 */

if (error_111) error_moan(ERR111);

/* Write MIDI output if required */

if (midi_filename != NULL)
  {
  if (verify) fprintf(stderr, "Writing MIDI file \"%s\" ...\n", midi_filename);
  midi_write();
  }

if (verify) fprintf(stderr, "PMW done\n");
return main_rc;
}

/* End of main.c */
