💾 Archived View for runjimmyrunrunyoufuckerrun.com › src › foreign › pmw › src › format.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 - 2019 */
/* Written by Philip Hazel, starting November 1991 */
/* This file last modified: August 2019 */
/* This file contains routines for formatting PMW-specific items of data for
printing, often in error messages. */
#include "pmwhdr.h"
static uschar *nlsharp[] = {
US" C", US"#C", US" D", US"#D", US" E", US" F",
US"#F", US" G", US"#G", US" A", US"#A", US" B" };
static uschar *nlflat[] = {
US" C", US"$D", US" D", US"$E", US" E", US" F",
US"$G", US" G", US"$A", US" A", US"$B", US" B" };
static uschar *octavestring[] = {
US"```", US"``", US"`", US"", US"'", US"''", US"'''", US"''''" };
static int notelengths[] = {
len_semibreve, len_minim, len_crotchet, len_quaver, len_squaver,
len_dsquaver, len_hdsquaver };
static uschar *notenames[] = {
US"semibreve", US"minim", US"crotchet", US"quaver", US"semiquaver",
US"demisemiquaver", US"hemidemisemiquaver" };
static uschar notefactor[] = { 2, 3, 5, 7, 11 };
/*************************************************
- Format a note length *
- ************************************************/
/* This function is used for "%l" formats in error messages. It turns a note
length into text, e.g. "4 crotchets".
Arguments:
buff where to put the text
length the note length
Returns: number of bytes placed in the buffer
static int
format_length(uschar *buff, int length)
{
usint i;
int count = 0;
int number = -1;
uschar *name = NULL;
/* Search for a whole number of a particular note type */
for (i = 0; i < sizeof(notelengths)/sizeof(int); i++)
{
if (length%notelengths[i] == 0)
{
number = length/notelengths[i];
name = notenames[i];
break;
}
}
/* If integral, it's a simple print */
if (number >= 0)
count = sprintf(CS buff, "%d %s%s", number, name, (number==1)?"":"s");
/* Otherwise, compute the fraction of a crotchet */
else
{
int d = len_crotchet;
name = US"of a crotchet";
if (length > len_crotchet)
{
count += sprintf(CS buff, "%d ", length/len_crotchet);
length = length%len_crotchet;
name = US"crotchets";
}
for (i = 0; i < sizeof(notefactor); i++)
{
int x = notefactor[i];
while (d%x == 0 && length%x == 0) { d /= x; length /= x; }
}
count += sprintf(CS buff+count, "%d/%d %s", length, d, name);
}
return count;
}
/*************************************************
- Format a fixed-point number *
- ************************************************/
/* All dimensions are held in fixed point with 3 decimal places. Some other
numbers are held this way too. This function is used for "%f" formats by
format_vsprintf() below. The number is right-justified to the field width if
the width is sufficiently large.
Arguments:
buff where to put the result
n the fixed point number
width the field width
Returns: number of bytes placed in the buffer
static int
format_fixed(uschar *buff, int n, int width)
{
int spacecount;
int count = 0;
div_t qr;
uschar tbuff[40];
if (n < 0)
{
tbuff[count++] = '-';
n = -n;
}
qr = div(n, 1000);
count += sprintf(CS tbuff + count, "%d", qr.quot);
if (qr.rem)
{
int r = qr.rem;
uschar *z;
if (r < 10) z = US".00";
else if (r < 100) z = US".0";
else z = US".";
if ((r%100) == 0) r /= 100;
else if ((r%10) == 0) r /= 10;
count += sprintf(CS tbuff + count, "%s%d", z, r);
}
spacecount = width - count;
if (spacecount <= 0) spacecount = 0; else Ustrcpy(buff, " ");
Ustrcpy(buff+spacecount, tbuff);
return count + spacecount;
}
/*************************************************
- Format a key signature *
- ************************************************/
/* This is used for "%k" format items.
Arguments:
buff buffer for the result
key the key signature
Returns: the number of bytes placed in the buffer
static int
format_key(uschar *buff, int key)
{
uschar *a = US"";
uschar *m = US"";
uschar *c = (key > 63)? US" cancel" : US"";
key &= 63;
if (key >= 21) { m = US"m"; key -= 21; }
if (key >= 14) { a = US"$"; key -= 14; }
else if (key >= 7) { a = US"#"; key -= 7; }
return sprintf(CS buff, "%c%s%s%s", "ABCDEFG"[key], a, m, c);
}
/*************************************************
- Format a time signature *
- ************************************************/
/* This is used for "%t" format items.
Arguments:
buff buffer for the result
time the time signature
Returns: the number of bytes placed in the buffer
static int
format_time(uschar *buff, int time)
{
int count = 0;
int m = (time & 0xFF0000) >> 16;
int n = (time & 0xFF00) >> 8;
int d = time & 255;
if (m != 1) count += sprintf(CS buff, "%d*", m);
if (d == time_common) return count + sprintf(CS buff+count, "C");
if (d == time_cut) return count + sprintf(CS buff+count, "A");
return count + sprintf(CS buff+count, "%d/%d", n, d);
}
/*************************************************
- Format a stave/page list *
- ************************************************/
/* This is used for "%L" format items.
Arguments:
buff buffer for the result
p the list pointer
Returns: the number of bytes placed in the buffer
static int
format_list(uschar *buff, stave_list *p)
{
int count = 0;
uschar *c = US"";
while (p != NULL)
{
if (p->first == p->last) count += sprintf(CS buff+count, "%s%d", c, p->first);
else count += sprintf(CS buff+count, "%s%d-%d", c, p->first, p->last);
c = US",";
p = p->next;
}
return count;
}
/*************************************************
- Format a bar number *
- ************************************************/
/* PMW keeps "true" bar numbers from 1 onwards. However, the existence of the
[nocount] directive defines a different set of bar numbers as seen by the user.
This procedure prints user bar numbers; for uncounted bars it prints "<n>.<m>".
Before calling format_vsprintf with a "%b" item, the caller should set
format_movt to point to the relevant movement block.
Arguments:
buff buffer for the result
n the bar number
Returns: the number of bytes placed in the buffer
static int
format_barnumber(uschar *buff, int n)
{
int a, b, p;
if (format_movt->barnovector[n+1] <= format_movt->barnovector[n])
return sprintf(CS buff, "%d",
n - format_movt->barnovector[n] + format_movt->baroffset);
p = n - 1;
while (p > 0 && format_movt->barnovector[p] < format_movt->barnovector[p+1])
p--;
a = p - format_movt->barnovector[p] + format_movt->baroffset;
b = n - p;
if (a == 0) b--;
if (b == 0) return sprintf(CS buff, "%d", a);
else return sprintf(CS buff, "%d.%d", a, b);
}
/*************************************************
- Format a movement phrase *
- ************************************************/
/* This is used for "%M" format items. If there is only one movement in
existence, it returns a null string; otherwise it returns "in movement <n>".
If we can't find the movement (a case that should never happen) return nothing,
as that is less misleading!
Argument: buffer for the result
Returns: the number of bytes placed in the buffer
static int
format_movement(uschar *buff)
{
int movtnumber = 1;
if (movement[2] == NULL) return 0; /* Only movement 1 exists */
while (format_movt != movement[movtnumber])
{ if (movement[++movtnumber] == NULL) return 0; }
return sprintf(CS buff, " in movement %d", movtnumber);
}
/*************************************************
- Format an absolute pitch *
- ************************************************/
/* This is used for "%P" format items. It is used when printing out information
about a stave. Zero means unset. As for barnumbers, format_movt must point to
the relevant movement. This is simply to have a look at the key signature in
order to decide whether to show "black" notes as sharps or flats.
Arguments:
buff buffer for result
pitch the pitch
Returns: the number of bytes placed in the buffer
static int
format_pitch(uschar *buff, int pitch)
{
int c;
if (pitch)
{
int octave = (pitch/12);
int note = pitch%12;
uschar **letters = (main_keysigtable[format_movt->key] >= 0)?
nlsharp : nlflat;
c = sprintf(CS buff, "%s%s", letters[note], octavestring[octave]);
while (c < 5) sprintf(CS buff+c++, " ");
}
else c = sprintf(CS buff, "unset");
return c;
}
/*************************************************
- Format using a format string (ap arguments) *
- ************************************************/
/* This function is a private vsprintf() that recognizes a number of additional
formatting codes (e.g. "%b" for a bar number). It is mainly used for error and
informational output.
Arguments:
buff where to put the formatted string
format the format string
ap the va_list variable for any arguments
Returns: the number of bytes placed in the buffer
int
format_vsprintf(uschar *buff, const char *format, va_list ap)
{
uschar *p = buff;
while (*format)
{
int width = 0;
BOOL lz = FALSE;
if (*format == '%')
{
if (isdigit(*(++format)))
{
lz = *format == '0';
do { width = width*10 + *format++ - '0'; } while (isdigit(*format));
}
switch (*format)
{
case 'b':
p += format_barnumber(p, va_arg(ap, int));
break;
case 'B':
p += sprintf(CS p, "%s", va_arg(ap, int)? "true" : "false");
break;
case 'c':
p += sprintf(CS p, "%c", va_arg(ap, int));
break;
case 'd':
p += sprintf(CS p, lz? "%0*d":"%*d", width, va_arg(ap, int));
width = 0;
break;
case 'f':
p += format_fixed(p, va_arg(ap, int), width);
break;
case 'g':
p += sprintf(CS p, lz? "%0*g":"%*g", width, va_arg(ap, double));
width = 0;
break;
case 'k':
p += format_key(p, va_arg(ap, int));
break;
case 'l':
p += format_length(p, va_arg(ap, int));
break;
case 'L':
p += format_list(p, va_arg(ap, stave_list *));
break;
case 'M':
p += format_movement(p);
break;
case 'P':
p += format_pitch(p, va_arg(ap, int));
break;
case 'p':
p += sprintf(CS p, "%p", (void *)va_arg(ap, uschar *));
break;
case 's':
p += sprintf(CS p, "%s", va_arg(ap, uschar *));
break;
case 't':
p += format_time(p, va_arg(ap, int));
break;
case 'x':
p += sprintf(CS p, lz? "%0*x":"%*x", width, va_arg(ap, int));
break;
case 'X':
p += sprintf(CS p, lz? "%0*X":"%*X", width, va_arg(ap, int));
break;
default:
*p++ = *format;
break;
}
format++;
}
else *p++ = *format++;
}
return p - buff;
}
/*************************************************
- Format using a format string (... arguments) *
- ************************************************/
/* This function is a private sprintf() that recognizes a number of additional
formatting codes (e.g. "%b" for a bar number). It is mainly used for error and
informational output.
Arguments:
buff where to put the formatted string
format the format string
... any arguments for the format
Returns: the number of bytes placed in the buffer
int
format_sprintf(uschar *buff, const char *format, ...)
{
va_list ap;
va_start(ap, format);
return format_vsprintf(buff, format, ap);
}
/* End of format.c */