💾 Archived View for runjimmyrunrunyoufuckerrun.com › src › foreign › pmw › src › main.c captured on 2021-12-17 at 13:26:06.
View Raw
More Information
-=-=-=-=-=-=-
/*************************************************
- 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;
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++;
}
}
/*************************************************
- 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 */