1 /*
2  * Formatting functions.
3  *
4  * This file is part of abcm2ps.
5  *
6  * Copyright (C) 1998-2017 Jean-François Moine
7  * Adapted from abc2ps, Copyright (C) 1996,1997 Michael Methfessel
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  */
14 
15 #include <stdlib.h>
16 #include <string.h>
17 #include <ctype.h>
18 
19 #include "abcm2ps.h"
20 
21 struct FORMAT cfmt;		/* current format for output */
22 
23 char *fontnames[MAXFONTS];		/* list of font names */
24 static char font_enc[MAXFONTS];		/* font encoding */
25 static char def_font_enc[MAXFONTS];	/* default font encoding */
26 static char used_font[MAXFONTS];	/* used fonts */
27 static float swfac_font[MAXFONTS];	/* width scale */
28 static int nfontnames;
29 static float staffwidth;
30 
31 /* format table */
32 static struct format {
33 	char *name;
34 	void *v;
35 	char type;
36 #define FORMAT_I 0	/* int */
37 #define FORMAT_R 1	/* float */
38 #define FORMAT_F 2	/* font spec */
39 #define FORMAT_U 3	/* float with unit */
40 #define FORMAT_B 4	/* boolean */
41 #define FORMAT_S 5	/* string */
42 	char subtype;		/* special cases - see code */
43 	short lock;
44 } format_tb[] = {
45 	{"abc2pscompat", &cfmt.abc2pscompat, FORMAT_B, 3},
46 	{"alignbars", &cfmt.alignbars, FORMAT_I, 0},
47 	{"aligncomposer", &cfmt.aligncomposer, FORMAT_I, 0},
48 	{"annotationfont", &cfmt.font_tb[ANNOTATIONFONT], FORMAT_F, 0},
49 	{"autoclef", &cfmt.autoclef, FORMAT_B, 0},
50 	{"barsperstaff", &cfmt.barsperstaff, FORMAT_I, 0},
51 	{"bgcolor", &cfmt.bgcolor, FORMAT_S, 0},
52 	{"botmargin", &cfmt.botmargin, FORMAT_U, 1},
53 	{"breaklimit", &cfmt.breaklimit, FORMAT_R, 3},
54 	{"breakoneoln", &cfmt.breakoneoln, FORMAT_B, 0},
55 	{"bstemdown", &cfmt.bstemdown, FORMAT_B, 0},
56 	{"cancelkey", &cfmt.cancelkey, FORMAT_B, 0},
57 	{"capo", &cfmt.capo, FORMAT_I, 0},
58 	{"combinevoices", &cfmt.combinevoices, FORMAT_I, 0},
59 	{"composerfont", &cfmt.font_tb[COMPOSERFONT], FORMAT_F, 0},
60 	{"composerspace", &cfmt.composerspace, FORMAT_U, 0},
61 	{"contbarnb", &cfmt.contbarnb, FORMAT_B, 0},
62 	{"continueall", &cfmt.continueall, FORMAT_B, 0},
63 	{"custos", &cfmt.custos, FORMAT_B, 0},
64 	{"dateformat", &cfmt.dateformat, FORMAT_S, 0},
65 	{"dblrepbar", &cfmt.dblrepbar, FORMAT_I, 2},
66 	{"decoerr", &cfmt.decoerr, FORMAT_B, 0},
67 	{"dynalign", &cfmt.dynalign, FORMAT_B, 0},
68 	{"footer", &cfmt.footer, FORMAT_S, 0},
69 	{"footerfont", &cfmt.font_tb[FOOTERFONT], FORMAT_F, 0},
70 	{"flatbeams", &cfmt.flatbeams, FORMAT_B, 0},
71 	{"gchordbox", &cfmt.gchordbox, FORMAT_B, 0},
72 	{"gchordfont", &cfmt.font_tb[GCHORDFONT], FORMAT_F, 3},
73 	{"graceslurs", &cfmt.graceslurs, FORMAT_B, 0},
74 	{"graceword", &cfmt.graceword, FORMAT_B, 0},
75 	{"gracespace", &cfmt.gracespace, FORMAT_I, 5},
76 	{"gutter", &cfmt.gutter, FORMAT_U, 0},
77 	{"header", &cfmt.header, FORMAT_S, 0},
78 	{"headerfont", &cfmt.font_tb[HEADERFONT], FORMAT_F, 0},
79 	{"historyfont", &cfmt.font_tb[HISTORYFONT], FORMAT_F, 0},
80 	{"hyphencont", &cfmt.hyphencont, FORMAT_B, 0},
81 	{"indent", &cfmt.indent, FORMAT_U, 0},
82 	{"infofont", &cfmt.font_tb[INFOFONT], FORMAT_F, 0},
83 	{"infoline", &cfmt.infoline, FORMAT_B, 0},
84 	{"infospace", &cfmt.infospace, FORMAT_U, 0},
85 	{"keywarn", &cfmt.keywarn, FORMAT_B, 0},
86 	{"landscape", &cfmt.landscape, FORMAT_B, 0},
87 	{"leftmargin", &cfmt.leftmargin, FORMAT_U, 1},
88 	{"lineskipfac", &cfmt.lineskipfac, FORMAT_R, 0},
89 	{"linewarn", &cfmt.linewarn, FORMAT_B, 0},
90 	{"maxshrink", &cfmt.maxshrink, FORMAT_R, 2},
91 	{"maxstaffsep", &cfmt.maxstaffsep, FORMAT_U, 0},
92 	{"maxsysstaffsep", &cfmt.maxsysstaffsep, FORMAT_U, 0},
93 	{"measurebox", &cfmt.measurebox, FORMAT_B, 0},
94 	{"measurefirst", &cfmt.measurefirst, FORMAT_I, 0},
95 	{"measurefont", &cfmt.font_tb[MEASUREFONT], FORMAT_F, 2},
96 	{"measurenb", &cfmt.measurenb, FORMAT_I, 0},
97 	{"micronewps", &cfmt.micronewps, FORMAT_B, 0},
98 	{"musicfont", &cfmt.musicfont, FORMAT_S, 1},
99 	{"musicspace", &cfmt.musicspace, FORMAT_U, 0},
100 	{"notespacingfactor", &cfmt.notespacingfactor, FORMAT_R, 1},
101 	{"oneperpage", &cfmt.oneperpage, FORMAT_B, 0},
102 	{"pageheight", &cfmt.pageheight, FORMAT_U, 1},
103 	{"pagewidth", &cfmt.pagewidth, FORMAT_U, 1},
104 	{"pagescale", &cfmt.scale, FORMAT_R, 0},
105 #ifdef HAVE_PANGO
106 	{"pango", &cfmt.pango, FORMAT_B, 2},
107 #endif
108 	{"parskipfac", &cfmt.parskipfac, FORMAT_R, 0},
109 	{"partsbox", &cfmt.partsbox, FORMAT_B, 0},
110 	{"partsfont", &cfmt.font_tb[PARTSFONT], FORMAT_F, 1},
111 	{"partsspace", &cfmt.partsspace, FORMAT_U, 0},
112 	{"pdfmark", &cfmt.pdfmark, FORMAT_I, 0},
113 	{"rbdbstop", &cfmt.rbdbstop, FORMAT_B, 0},
114 	{"rbmax", &cfmt.rbmax, FORMAT_I, 0},
115 	{"rbmin", &cfmt.rbmin, FORMAT_I, 0},
116 	{"repeatfont", &cfmt.font_tb[REPEATFONT], FORMAT_F, 0},
117 	{"rightmargin", &cfmt.rightmargin, FORMAT_U, 1},
118 //	{"scale", &cfmt.scale, FORMAT_R, 0},
119 	{"setdefl", &cfmt.setdefl, FORMAT_B, 0},
120 //	{"shifthnote", &cfmt.shiftunison, FORMAT_B, 0},	/*to remove*/
121 	{"shiftunison", &cfmt.shiftunison, FORMAT_I, 0},
122 	{"slurheight", &cfmt.slurheight, FORMAT_R, 0},
123 	{"splittune", &cfmt.splittune, FORMAT_I, 1},
124 	{"squarebreve", &cfmt.squarebreve, FORMAT_B, 0},
125 	{"staffnonote", &cfmt.staffnonote, FORMAT_I, 0},
126 	{"staffsep", &cfmt.staffsep, FORMAT_U, 0},
127 	{"staffwidth", &staffwidth, FORMAT_U, 2},
128 	{"stemheight", &cfmt.stemheight, FORMAT_R, 0},
129 	{"straightflags", &cfmt.straightflags, FORMAT_B, 0},
130 	{"stretchlast", &cfmt.stretchlast, FORMAT_R, 2},
131 	{"stretchstaff", &cfmt.stretchstaff, FORMAT_B, 0},
132 	{"subtitlefont", &cfmt.font_tb[SUBTITLEFONT], FORMAT_F, 0},
133 	{"subtitlespace", &cfmt.subtitlespace, FORMAT_U, 0},
134 	{"sysstaffsep", &cfmt.sysstaffsep, FORMAT_U, 0},
135 	{"tempofont", &cfmt.font_tb[TEMPOFONT], FORMAT_F, 0},
136 	{"textfont", &cfmt.font_tb[TEXTFONT], FORMAT_F, 0},
137 	{"textoption", &cfmt.textoption, FORMAT_I, 4},
138 	{"textspace", &cfmt.textspace, FORMAT_U, 0},
139 	{"titlecaps", &cfmt.titlecaps, FORMAT_B, 0},
140 	{"titlefont", &cfmt.font_tb[TITLEFONT], FORMAT_F, 0},
141 	{"titleformat", &cfmt.titleformat, FORMAT_S, 0},
142 	{"titleleft", &cfmt.titleleft, FORMAT_B, 0},
143 	{"titlespace", &cfmt.titlespace, FORMAT_U, 0},
144 	{"titletrim", &cfmt.titletrim, FORMAT_I, 0},
145 	{"timewarn", &cfmt.timewarn, FORMAT_B, 0},
146 	{"topmargin", &cfmt.topmargin, FORMAT_U, 1},
147 	{"topspace", &cfmt.topspace, FORMAT_U, 0},
148 	{"tuplets", &cfmt.tuplets, FORMAT_I, 3},
149 	{"vocalfont", &cfmt.font_tb[VOCALFONT], FORMAT_F, 0},
150 	{"vocalspace", &cfmt.vocalspace, FORMAT_U, 0},
151 	{"voicefont", &cfmt.font_tb[VOICEFONT], FORMAT_F, 0},
152 	{"wordsfont", &cfmt.font_tb[WORDSFONT], FORMAT_F, 0},
153 	{"wordsspace", &cfmt.wordsspace, FORMAT_U, 0},
154 	{"writefields", &cfmt.fields, FORMAT_B, 1},
155 	{0, 0, 0, 0}		/* end of table */
156 };
157 
158 static const char helvetica[] = "Helvetica";
159 static const char times[] = "Times-Roman";
160 static const char times_bold[] = "Times-Bold";
161 static const char times_italic[] = "Times-Italic";
162 static const char sans[] = "sans-serif";
163 static const char serif[] = "serif";
164 static const char serif_italic[] = "serif-Italic";
165 static const char serif_bold[] = "serif-Bold";
166 
167 /* -- search a font and add it if not yet defined -- */
get_font(const char * fname,int encoding)168 static int get_font(const char *fname, int encoding)
169 {
170 	int fnum;
171 
172 	/* get or set the default encoding */
173 	for (fnum = nfontnames; --fnum >= 0; )
174 		if (strcmp(fname, fontnames[fnum]) == 0) {
175 			if (encoding < 0)
176 				encoding = def_font_enc[fnum];
177 			if (encoding == font_enc[fnum])
178 				return fnum;		/* font found */
179 			break;
180 		}
181 	while (--fnum >= 0) {
182 		if (strcmp(fname, fontnames[fnum]) == 0
183 		 && encoding == font_enc[fnum])
184 			return fnum;
185 	}
186 
187 	/* add the font */
188 	if (nfontnames >= MAXFONTS) {
189 		error(1, NULL, "Too many fonts");
190 		return 0;
191 	}
192 	if (epsf <= 1 && !svg) {
193 		if (file_initialized > 0)
194 			error(1, NULL,
195 			      "Cannot have a new font when the output file is opened");
196 		if (strchr(fname, ' ') != NULL) {
197 			error(1, NULL,
198 				"PostScript fonts cannot have names with spaces");
199 			return 0;
200 		}
201 	}
202 	fnum = nfontnames++;
203 	fontnames[fnum] = strdup(fname);
204 	if (encoding < 0)
205 		encoding = 0;
206 	font_enc[fnum] = encoding;
207 
208 	return fnum;
209 }
210 
211 /* -- set a dynamic font -- */
dfont_set(struct FONTSPEC * f)212 static int dfont_set(struct FONTSPEC *f)
213 {
214 	int i;
215 
216 	for (i = FONT_DYN; i < cfmt.ndfont; i++) {
217 		if (cfmt.font_tb[i].fnum == f->fnum
218 		    && cfmt.font_tb[i].size == f->size)
219 			return i;
220 	}
221 	if (i >= FONT_MAX - 1) {
222 		error(1, NULL, "Too many dynamic fonts");
223 		return FONT_MAX - 1;
224 	}
225 	memcpy(&cfmt.font_tb[i], f, sizeof cfmt.font_tb[0]);
226 	cfmt.ndfont = i + 1;
227 	return i;
228 }
229 
230 /* -- define a font -- */
fontspec(struct FONTSPEC * f,const char * name,int encoding,float size)231 static void fontspec(struct FONTSPEC *f,
232 		     const char *name,
233 		     int encoding,
234 		     float size)
235 {
236 	if (name)
237 		f->fnum = get_font(name, encoding);
238 	else
239 		name = fontnames[f->fnum];
240 	f->size = size;
241 	f->swfac = size;
242 	if (swfac_font[f->fnum] != 0) {
243 		f->swfac *= swfac_font[f->fnum];
244 	} else if (strncmp(name, times, 5) == 0
245 		|| strncmp(name, serif, 5) == 0) {
246 		if (strcmp(name, times_bold) == 0
247 		 || strcmp(name, serif_bold) == 0)
248 			f->swfac *= 1.05;
249 	} else if (strcmp(name, "Helvetica-Bold") == 0) {
250 		f->swfac *= 1.15;
251 	} else if (strncmp(name, helvetica, 9) == 0
252 		|| strncmp(name, "Palatino", 8) == 0) {
253 		f->swfac *= 1.1;
254 	} else if (strncmp(name, "Courier", 7) == 0) {
255 		f->swfac *= 1.35;
256 	} else {
257 		f->swfac *= 1.1;		/* unknown font */
258 	}
259 	if (f == &cfmt.font_tb[GCHORDFONT])
260 		cfmt.gcf = dfont_set(f);
261 	else if (f == &cfmt.font_tb[ANNOTATIONFONT])
262 		cfmt.anf = dfont_set(f);
263 	else if (f == &cfmt.font_tb[VOCALFONT])
264 		cfmt.vof = dfont_set(f);
265 }
266 
267 /* -- output the font definitions with their encodings -- */
268 /* This output must occurs after user PostScript definitions because
269  * these ones may change the default behaviour */
define_fonts(void)270 void define_fonts(void)
271 {
272 	int i;
273 	static char *mkfont =
274 	"/mkfont{findfont dup length 1 add dict begin\n"
275 	"	{1 index/FID ne{def}{pop pop}ifelse}forall\n"
276 	"	CharStrings/double_sharp known not{\n"
277 	"	    /CharStrings CharStrings dup length dict copy def\n"
278 	"	    FontMatrix 0 get 1 eq{\n"
279 	"		CharStrings/sharp{pop .46 0 setcharwidth .001 dup scale usharp ufill}bind put\n"
280 	"		CharStrings/flat{pop .46 0 setcharwidth .001 dup scale uflat ufill}bind put\n"
281 	"		CharStrings/natural{pop .40 0 setcharwidth .001 dup scale unat ufill}bind put\n"
282 	"		CharStrings/double_sharp{pop .46 0 setcharwidth .001 dup scale udblesharp ufill}bind put\n"
283 	"		CharStrings/double_flat{pop .50 0 setcharwidth .001 dup scale udbleflat ufill}bind put\n"
284 	"	    }{\n"
285 	"		CharStrings/sharp{pop 460 0 setcharwidth usharp ufill}bind put\n"
286 	"		CharStrings/flat{pop 460 0 setcharwidth uflat ufill}bind put\n"
287 	"		CharStrings/natural{pop 400 0 setcharwidth unat ufill}bind put\n"
288 	"		CharStrings/double_sharp{pop 460 0 setcharwidth udblesharp ufill}bind put\n"
289 	"		CharStrings/double_flat{pop 500 0 setcharwidth udbleflat ufill}bind put\n"
290 	"	    }ifelse\n"
291 	"	}if currentdict definefont pop end}!\n";
292 
293 	fputs(mkfont, fout);
294 	make_font_list();
295 	for (i = 0; i < nfontnames; i++) {
296 		if (used_font[i])
297 			define_font(fontnames[i], i, font_enc[i]);
298 	}
299 }
300 
301 /* -- mark the used fonts -- */
make_font_list(void)302 void make_font_list(void)
303 {
304 	struct FORMAT *f;
305 	int i;
306 
307 	f = &cfmt;
308 	for (i = FONT_UMAX; i < FONT_DYN; i++)
309 		used_font[f->font_tb[i].fnum] = 1;
310 }
311 
312 /* -- set the name of an information header type -- */
313 /* the argument is
314  *	<letter> [ <possibly quoted string> ]
315  * this information is kept in the 'I' information */
set_infoname(char * p)316 static void set_infoname(char *p)
317 {
318 	struct SYMBOL *s, *prev;
319 
320 	if (*p == 'I')
321 		return;
322 	s = info['I' - 'A'];
323 	prev = NULL;
324 	while (s) {
325 		if (s->text[0] == *p)
326 			break;
327 		prev = s;
328 		s = s->next;
329 	}
330 	if (p[1] == '\0') {		/* if delete */
331 		if (s) {
332 			if (!prev)
333 				info['I' - 'A'] = s->next;
334 			else if ((prev->next = s->next) != 0)
335 				prev->next->prev = prev;
336 		}
337 		return;
338 	}
339 	if (!s) {
340 		s = (struct SYMBOL *) getarena(sizeof *s);
341 		memset(s, 0, sizeof *s);
342 		if (!prev)
343 			info['I' - 'A'] = s;
344 		else {
345 			prev->next = s;
346 			s->prev = prev;
347 		}
348 	}
349 	s->text = (char *) getarena(strlen(p) + 1);
350 	strcpy(s->text, p);
351 }
352 
353 /* -- set the default format -- */
354 /* this function is called only once, at abcm2ps startup time */
set_format(void)355 void set_format(void)
356 {
357 	struct FORMAT *f;
358 
359 	f = &cfmt;
360 	memset(f, 0, sizeof *f);
361 	f->pageheight = PAGEHEIGHT;
362 	f->pagewidth = PAGEWIDTH;
363 	f->leftmargin = MARGIN;
364 	f->rightmargin = MARGIN;
365 	f->topmargin = 1.0 CM;
366 	f->botmargin = 1.0 CM;
367 	f->topspace = 22.0 PT;
368 	f->titlespace = 6.0 PT;
369 	f->subtitlespace = 3.0 PT;
370 	f->composerspace = 6.0 PT;
371 	f->musicspace = 6.0 PT;
372 	f->partsspace = 8.0 PT;
373 	f->staffsep = 46.0 PT;
374 	f->sysstaffsep = 34.0 PT;
375 	f->maxstaffsep = 2000.0 PT;
376 	f->maxsysstaffsep = 2000.0 PT;
377 	f->vocalspace = 10 PT;
378 	f->textspace = 14 PT;
379 	f->scale = 1.0;
380 	f->slurheight = 1.0;
381 	f->maxshrink = 0.65;
382 	f->breaklimit = 0.7;
383 	f->stretchlast = 0.25;
384 	f->stretchstaff = 1;
385 	f->graceslurs = 1;
386 	f->hyphencont = 1;
387 	f->lineskipfac = 1.1;
388 	f->parskipfac = 0.4;
389 	f->measurenb = -1;
390 	f->measurefirst = 1;
391 	f->autoclef = 1;
392 	f->breakoneoln = 1;
393 	f->cancelkey = 1;
394 	f->dblrepbar = (B_COL << 12) + (B_CBRA << 8) + (B_OBRA << 4) + B_COL;
395 	f->decoerr = 1;
396 	f->dynalign = 1;
397 	f->keywarn = 1;
398 	f->linewarn = 1;
399 #ifdef HAVE_PANGO
400 	if (!svg && epsf <= 1)
401 		f->pango = 1;
402 	else
403 		lock_fmt(&cfmt.pango);	/* SVG output does not use panga */
404 #endif
405 	f->rbdbstop = 1;
406 	f->rbmax = 4;
407 	f->rbmin = 2;
408 	f->staffnonote = 1;
409 	f->titletrim = 1;
410 	f->aligncomposer = A_RIGHT;
411 	f->notespacingfactor = 1.414;
412 	f->stemheight = STEM;
413 #ifndef WIN32
414 	f->dateformat = strdup("%b %e, %Y %H:%M");
415 #else
416 	f->dateformat = strdup("%b %#d, %Y %H:%M");
417 #endif
418 	f->gracespace = (65 << 16) | (80 << 8) | 120;	/* left-inside-right - unit 1/10 pt */
419 	f->textoption = T_LEFT;
420 	f->ndfont = FONT_DYN;
421 	if (svg || epsf > 2) {		// SVG output
422 		fontspec(&f->font_tb[ANNOTATIONFONT], sans, 0, 12.0);
423 		fontspec(&f->font_tb[COMPOSERFONT], serif_italic, 0, 14.0);
424 		fontspec(&f->font_tb[FOOTERFONT], serif, 0, 16.0);
425 		fontspec(&f->font_tb[GCHORDFONT], sans, 0, 12.0);
426 		fontspec(&f->font_tb[HEADERFONT], serif, 0, 16.0);
427 		fontspec(&f->font_tb[HISTORYFONT], serif, 0, 16.0);
428 		fontspec(&f->font_tb[INFOFONT],	serif_italic, 0, 14.0); /* same as composer by default */
429 		fontspec(&f->font_tb[MEASUREFONT], serif_italic, 0, 14.0);
430 		fontspec(&f->font_tb[PARTSFONT], serif, 0, 15.0);
431 		fontspec(&f->font_tb[REPEATFONT], serif, 0, 13.0);
432 		fontspec(&f->font_tb[SUBTITLEFONT], serif, 0, 16.0);
433 		fontspec(&f->font_tb[TEMPOFONT], serif_bold, 0, 15.0);
434 		fontspec(&f->font_tb[TEXTFONT],	serif, 0, 16.0);
435 		fontspec(&f->font_tb[TITLEFONT], serif, 0, 20.0);
436 		fontspec(&f->font_tb[VOCALFONT], serif_bold, 0, 13.0);
437 		fontspec(&f->font_tb[VOICEFONT], serif_bold, 0, 13.0);
438 		fontspec(&f->font_tb[WORDSFONT], serif, 0, 16.0);
439 	} else {			// PS output
440 		fontspec(&f->font_tb[ANNOTATIONFONT], helvetica, 0, 12.0);
441 		fontspec(&f->font_tb[COMPOSERFONT], times_italic, 0, 14.0);
442 		fontspec(&f->font_tb[FOOTERFONT], times, 0, 16.0);
443 		fontspec(&f->font_tb[GCHORDFONT], helvetica, 0, 12.0);
444 		fontspec(&f->font_tb[HEADERFONT], times, 0, 16.0);
445 		fontspec(&f->font_tb[HISTORYFONT], times, 0, 16.0);
446 		fontspec(&f->font_tb[INFOFONT],	times_italic, 0, 14.0); /* same as composer by default */
447 		fontspec(&f->font_tb[MEASUREFONT], times_italic, 0, 14.0);
448 		fontspec(&f->font_tb[PARTSFONT], times, 0, 15.0);
449 		fontspec(&f->font_tb[REPEATFONT], times, 0, 13.0);
450 		fontspec(&f->font_tb[SUBTITLEFONT], times, 0, 16.0);
451 		fontspec(&f->font_tb[TEMPOFONT], times_bold, 0, 15.0);
452 		fontspec(&f->font_tb[TEXTFONT],	times, 0, 16.0);
453 		fontspec(&f->font_tb[TITLEFONT], times, 0, 20.0);
454 		fontspec(&f->font_tb[VOCALFONT], times_bold, 0, 13.0);
455 		fontspec(&f->font_tb[VOICEFONT], times_bold, 0, 13.0);
456 		fontspec(&f->font_tb[WORDSFONT], times, 0, 16.0);
457 	}
458 	f->fields[0] = (1 << ('C' - 'A'))
459 		| (1 << ('M' - 'A'))
460 		| (1 << ('O' - 'A'))
461 		| (1 << ('P' - 'A'))
462 		| (1 << ('Q' - 'A'))
463 		| (1 << ('T' - 'A'))
464 		| (1 << ('W' - 'A'));
465 	f->fields[1] = (1 << ('w' - 'a'));
466 	set_infoname("R \"Rhythm: \"");
467 	set_infoname("B \"Book: \"");
468 	set_infoname("S \"Source: \"");
469 	set_infoname("D \"Discography: \"");
470 	set_infoname("N \"Notes: \"");
471 	set_infoname("Z \"Transcription: \"");
472 	set_infoname("H \"History: \"");
473 }
474 
475 /* -- print the current format -- */
print_format(void)476 void print_format(void)
477 {
478 	struct format *fd;
479 static char *yn[2] = {"no","yes"};
480 
481 	for (fd = format_tb; fd->name; fd++) {
482 		printf("%-15s ", fd->name);
483 		switch (fd->type) {
484 		case FORMAT_B:
485 			switch (fd->subtype) {
486 #ifdef HAVE_PANGO
487 			case 2:				/* pango = 0, 1 or 2 */
488 				if (cfmt.pango == 2) {
489 					printf("2\n");
490 					break;
491 				}
492 				/* fall thru */
493 #endif
494 			default:
495 			case 0:
496 				printf("%s\n", yn[*((int *) fd->v)]);
497 				break;
498 			case 1: {			/* writefields */
499 				int i;
500 
501 				for (i = 0; i < 32; i++) {
502 					if (cfmt.fields[0] & (1 << i))
503 						printf("%c", (char) ('A' + i));
504 					if (cfmt.fields[1] & (1 << i))
505 						printf("%c", (char) ('a' + i));
506 				}
507 				printf("\n");
508 				break;
509 			    }
510 			}
511 			break;
512 		case FORMAT_I:
513 			switch (fd->subtype) {
514 			default:
515 				printf("%d\n", *((int *) fd->v));
516 				break;
517 			case 2: {		/* dblrepbar */
518 				int v;
519 				char tmp[16], *p;
520 
521 				p = &tmp[sizeof tmp - 1];
522 				*p = '\0';
523 				for (v = cfmt.dblrepbar; v != 0; v >>= 4) {
524 					switch (v & 0x0f) {
525 					case B_BAR:
526 						*--p = '|';
527 						break;
528 					case B_OBRA:
529 						*--p = '[';
530 						break;
531 					case B_CBRA:
532 						*--p = ']';
533 						break;
534 					default:
535 //					case B_COL:
536 						*--p = ':';
537 						break;
538 					}
539 				}
540 				printf("%s\n", p);
541 				break;
542 			    }
543 			case 3:			/* tuplets */
544 				printf("%d %d %d %d\n",
545 					cfmt.tuplets >> 12,
546 					(cfmt.tuplets >> 8) & 0x0f,
547 					(cfmt.tuplets >> 4) & 0x0f,
548 					cfmt.tuplets & 0x0f);
549 				break;
550 //			case 4:			/* textoption */
551 //				break;
552 			case 5:			/* gracespace */
553 				printf("%d.%d %d.%d %d.%d\n",
554 					(cfmt.gracespace >> 16) / 10,
555 					(cfmt.gracespace >> 16) % 10,
556 					((cfmt.gracespace >> 8) & 0xff) / 10,
557 					((cfmt.gracespace >> 8) & 0xff) % 10,
558 					(cfmt.gracespace & 0xff) / 10,
559 					(cfmt.gracespace & 0xff) % 10);
560 				break;
561 			}
562 			break;
563 		case FORMAT_R:
564 			printf("%.2f\n", *((float *) fd->v));
565 			break;
566 		case FORMAT_F: {
567 			struct FONTSPEC *s;
568 
569 			s = (struct FONTSPEC *) fd->v;
570 			printf("%s", fontnames[s->fnum]);
571 			printf(" %s", font_enc[s->fnum] ? "native" : "utf-8");
572 			printf(" %.1f", s->size);
573 			if ((fd->subtype == 1 && cfmt.partsbox)
574 			 || (fd->subtype == 2 && cfmt.measurebox)
575 			 || (fd->subtype == 3 && cfmt.gchordbox))
576 				printf(" box");
577 			printf("\n");
578 			break;
579 		}
580 		case FORMAT_U:
581 			if (fd->subtype == 0)
582 				printf("%.2f\n", *((float *) fd->v));
583 			else if (fd->subtype == 1)
584 				printf("%.2fcm\n", *((float *) fd->v) / (1 CM));
585 			else //if (fd->subtype == 2)
586 				printf("%.2fcm\n",
587 					(cfmt.pagewidth
588 						- cfmt.leftmargin
589 						- cfmt.rightmargin)
590 					/ (1 CM));
591 			break;
592 		case FORMAT_S:
593 			printf("\"%s\"\n",
594 				*((char **) fd->v) != 0 ? *((char **) fd->v) : "");
595 			break;
596 		}
597 	}
598 }
599 
600 /* -- get a number with a unit -- */
601 /* The type may be
602  *	= 0: internal space - convert 'cm' and 'in' to 72 PPI
603  *	!= 0: page dimensions and margins
604  */
scan_u(char * str,int type)605 float scan_u(char *str, int type)
606 {
607 	float a;
608 	int nch;
609 
610 	if (sscanf(str, "%f%n", &a, &nch) == 1) {
611 		if (str[nch] == '\0' || str[nch] == ' ') {
612 			if (type != 0)
613 				error(0, NULL, "Bad unit \"%s\"", str);
614 			return a PT;
615 		}
616 		if (!strncasecmp(str + nch, "pt", 2))
617 			return a PT;
618 		if (!strncasecmp(str + nch, "cm", 2))
619 			return type ? a CM : a * 28.35;
620 		if (!strncasecmp(str + nch, "in", 2))
621 			return type ? a IN : a * 72;
622 	}
623 	error(1, NULL, "Unknown unit value \"%s\"", str);
624 	return 20 PT;
625 }
626 
627 /* -- get an encoding -- */
parse_encoding(char * p)628 static int parse_encoding(char *p)
629 {
630 	return strncasecmp(p, "native", 6) == 0;
631 }
632 
633 /* -- get a position -- */
get_posit(char * p)634 static int get_posit(char *p)
635 {
636 	if (strcmp(p, "up") == 0
637 	 || strcmp(p, "above") == 0)
638 		return SL_ABOVE;
639 	if (strcmp(p, "down") == 0
640 	 || strcmp(p, "below") == 0
641 	 || strcmp(p, "under") == 0)
642 		return SL_BELOW;
643 	if (strcmp(p, "hidden") == 0
644 	 || strcmp(p, "opposite") == 0)
645 		return SL_HIDDEN;
646 	if (strcmp(p, "auto") == 0)
647 		return 0;		/* auto (!= SL_AUTO) */
648 	return -1;
649 }
650 
651 /* -- get the option for text -- */
get_textopt(char * p)652 int get_textopt(char *p)
653 {
654 	if (strncmp(p, "align", 5) == 0
655 	 || strncmp(p, "justify", 7) == 0)
656 		return T_JUSTIFY;
657 	if (strncmp(p, "ragged", 6) == 0
658 	 || strncmp(p, "fill", 4) == 0)
659 		return T_FILL;
660 	if (strncmp(p, "center", 6) == 0)
661 		return T_CENTER;
662 	if (strncmp(p, "skip", 4) == 0)
663 		return T_SKIP;
664 	if (strncmp(p, "right", 5) == 0)
665 		return T_RIGHT;
666 	return T_LEFT;
667 }
668 
669 /* -- get the double repeat bar -- */
get_dblrepbar(char * p)670 static int get_dblrepbar(char *p)
671 {
672 	int bar_type;
673 
674 	bar_type = 0;
675 	for (;;) {
676 		switch (*p++) {
677 		case '|':
678 			bar_type <<= 4;
679 			bar_type |= B_BAR;
680 			continue;
681 		case '[':
682 			bar_type <<= 4;
683 			bar_type |= B_OBRA;
684 			continue;
685 		case ']':
686 			bar_type <<= 4;
687 			bar_type |= B_CBRA;
688 			continue;
689 		case ':':
690 			bar_type <<= 4;
691 			bar_type |= B_COL;
692 			continue;
693 		default:
694 			break;
695 		}
696 		break;
697 	}
698 	return bar_type;
699 }
700 
701 /* -- get a boolean value -- */
get_bool(char * p)702 int get_bool(char *p)
703 {
704 	switch (*p) {
705 	case '\0':
706 	case '1':
707 	case 'y':
708 	case 'Y':
709 	case 't':
710 	case 'T':
711 		return 1;
712 	case '0':
713 	case 'n':
714 	case 'N':
715 	case 'f':
716 	case 'F':
717 		break;
718 	default:
719 		error(0, NULL, "Unknown logical '%s' - false assumed", p);
720 		break;
721 	}
722 	return 0;
723 }
724 
725 /* -- get a font specifier -- */
g_fspc(char * p,struct FONTSPEC * f)726 static void g_fspc(char *p,
727 		   struct FONTSPEC *f)
728 {
729 	char fname[80];
730 	int encoding;
731 	float fsize;
732 
733 	p = get_str(fname, p, sizeof fname);
734 	if (isalpha((unsigned char) *p) || *p == '*') {
735 		if (*p == '*')
736 			encoding = font_enc[f->fnum];
737 		else
738 			encoding = parse_encoding(p);
739 		while (*p != '\0' && !isspace((unsigned char) *p))
740 			p++;
741 		while (isspace((unsigned char) *p))
742 			p++;
743 	} else {
744 		encoding = -1;
745 	}
746 	fsize = f->size;
747 	if (*p != '\0' && *p != '*') {
748 		char *q;
749 		float v;
750 
751 		v = strtod(p, &q);
752 		if (v <= 0 || (*q != '\0' && *q != ' '))
753 			error(1, NULL, "Bad font size '%s'", p);
754 		else
755 			fsize = v;
756 	}
757 	fontspec(f,
758 		 strcmp(fname, "*") != 0 ? fname : 0,
759 		 encoding,
760 		 fsize);
761 	if (file_initialized <= 0)
762 		used_font[f->fnum] = 1;
763 	if (f - cfmt.font_tb == outft)
764 		outft = -1;
765 #ifdef HAVE_PANGO
766 	pg_reset_font();
767 #endif
768 }
769 
770 /* -- parse a 'tablature' definition -- */
771 /* %%tablature
772  *	[#<nunmber (1..MAXTBLT)>]
773  *	[pitch=<instrument pitch (<note> # | b)>]
774  *	[[<head width>]
775  *	 <height above>]
776  *	<height under>
777  *	<head function>
778  *	<note function>
779  *	[<bar function>]
780  */
tblt_parse(char * p)781 struct tblt_s *tblt_parse(char *p)
782 {
783 	struct tblt_s *tblt;
784 	int n;
785 	char *q;
786 	static const char notes_tb[] = "CDEFGABcdefgab";
787 	static const char pitch_tb[14] = {60, 62, 64, 65, 67, 69, 71,
788 					  72, 74, 76, 77, 79, 81, 83};
789 
790 	/* number */
791 	if (*p == '#') {
792 		p++;
793 		n = *p++ - '0' - 1;
794 		if ((unsigned) n >= MAXTBLT
795 		 || (*p != '\0' && *p != ' ')) {
796 			error(1, NULL, "Invalid number in %%%%tablature");
797 			return 0;
798 		}
799 		if (*p == '\0')
800 			return tblts[n];
801 		while (isspace((unsigned char) *p))
802 			p++;
803 	} else {
804 		n = -1;
805 	}
806 
807 	/* pitch */
808 	tblt = malloc(sizeof *tblt);
809 	memset(tblt, 0, sizeof *tblt);
810 	if (strncmp(p, "pitch=", 6) == 0) {
811 		p += 6;
812 		if (*p == '^' || *p == '_') {
813 			if (*p == '^') {
814 				tblt->pitch++;
815 				tblt->instr[1] = '#';
816 			} else {
817 				tblt->pitch--;
818 				tblt->instr[1] = 'b';
819 			}
820 			p++;
821 		}
822 		if (*p == '\0' || (q = strchr(notes_tb, *p)) == NULL) {
823 			error(1, NULL, "Invalid pitch in %%%%tablature");
824 			return 0;
825 		}
826 		tblt->pitch += pitch_tb[q - notes_tb];
827 		tblt->instr[0] = toupper(*p++);
828 		while (*p == '\'' || *p == ',') {
829 			if (*p++ == '\'')
830 				tblt->pitch += 12;
831 			else
832 				tblt->pitch -= 12;
833 		}
834 		if (*p == '#' || *p == 'b') {
835 			if (*p == '#')
836 				tblt->pitch++;
837 			else
838 				tblt->pitch--;
839 			tblt->instr[1] = *p++;
840 		}
841 		while (*p == '\'' || *p == ',') {
842 			if (*p++ == '\'')
843 				tblt->pitch += 12;
844 			else
845 				tblt->pitch -= 12;
846 		}
847 		while (isspace((unsigned char) *p))
848 			p++;
849 	}
850 
851 	/* width and heights */
852 	if (!isdigit(*p)) {
853 		error(1, NULL, "Invalid width/height in %%%%tablature");
854 		return 0;
855 	}
856 	tblt->hu = scan_u(p, 0);
857 	while (*p != '\0' && !isspace((unsigned char) *p))
858 		p++;
859 	while (isspace((unsigned char) *p))
860 		p++;
861 	if (isdigit(*p)) {
862 		tblt->ha = tblt->hu;
863 		tblt->hu = scan_u(p, 0);
864 		while (*p != '\0' && !isspace((unsigned char) *p))
865 			p++;
866 		while (isspace((unsigned char) *p))
867 			p++;
868 		if (isdigit(*p)) {
869 			tblt->wh = tblt->ha;
870 			tblt->ha = tblt->hu;
871 			tblt->hu = scan_u(p, 0);
872 			while (*p != '\0' && !isspace((unsigned char) *p))
873 				p++;
874 			while (isspace((unsigned char) *p))
875 				p++;
876 		}
877 	}
878 	if (*p == '\0')
879 		goto err;
880 
881 	/* PS functions */
882 	p = strdup(p);
883 	tblt->head = p;
884 	while (*p != '\0' && !isspace((unsigned char) *p))
885 		p++;
886 	if (*p == '\0')
887 		goto err;
888 	*p++ = '\0';
889 	while (isspace((unsigned char) *p))
890 		p++;
891 	tblt->note = p;
892 	while (*p != '\0' && !isspace((unsigned char) *p))
893 		p++;
894 	if (*p != '\0') {
895 		*p++ = '\0';
896 		while (isspace((unsigned char) *p))
897 			p++;
898 		tblt->bar = p;
899 		while (*p != '\0' && !isspace((unsigned char) *p))
900 			p++;
901 		if (*p != '\0')
902 			goto err;
903 	}
904 
905 	/* memorize the definition */
906 	if (n >= 0)
907 		tblts[n] = tblt;
908 	return tblt;
909 err:
910 	error(1, NULL, "Wrong values in %%%%tablature");
911 	return 0;
912 }
913 
914 /* functions to set a voice parameter */
915 #define F_SET_PAR(param) \
916 static void set_ ## param(struct VOICE_S *p_voice, int val)\
917 {\
918 	p_voice->posit.param = val;\
919 }
920 F_SET_PAR(dyn)
921 F_SET_PAR(gch)
922 F_SET_PAR(orn)
923 F_SET_PAR(voc)
924 F_SET_PAR(vol)
925 F_SET_PAR(std)
926 F_SET_PAR(gsd)
927 
928 struct vpar {
929 	char *name;
930 	void (*f)(struct VOICE_S *p_voice, int val);
931 };
932 static const struct vpar vpar_tb[] = {
933 	{"dynamic", set_dyn},	/* 0 */
934 	{"gchord", set_gch},	/* 1 */
935 	{"gstemdir", set_gsd},	/* 2 */
936 	{"ornament", set_orn},	/* 3 */
937 	{"stemdir", set_std},	/* 4 */
938 	{"vocal", set_voc},	/* 5 */
939 	{"volume", set_vol},	/* 6 */
940 #ifndef WIN32
941 	{}
942 #else
943 	{NULL, NULL, 0}
944 #endif
945 };
946 /* -- set a voice parameter -- */
set_voice_param(struct VOICE_S * p_voice,int state,char * w,char * p)947 void set_voice_param(struct VOICE_S *p_voice,	/* current voice */
948 			int state,		/* tune state */
949 			char *w,		/* keyword */
950 			char *p)		/* argument */
951 {
952 	const struct vpar *vpar, *vpar2 = NULL;
953 	int i, l, val;
954 
955 	l = strlen(w);
956 	for (vpar = vpar_tb; vpar->name; vpar++) {
957 		if (strncmp(w, vpar->name, l))
958 			continue;
959 //		if (!isdigit(*p))
960 			val = get_posit(p);
961 //		else
962 //			val = strtol(p, NULL, 10);
963 //		if ((unsigned) val > vpar->max)
964 //			goto err;
965 		break;
966 	}
967 	if (!vpar->name) {	/* compatibility with previous versions */
968 		val = -1;
969 		switch (*w) {
970 		case 'e':
971 			if (strcmp(w, "exprabove") == 0) {
972 				vpar = &vpar[0];	/* dyn */
973 				vpar2 = &vpar[6];	/* vol */
974 				if (get_bool(p))
975 					val = SL_ABOVE;
976 				else
977 					val = SL_BELOW;
978 				break;
979 			}
980 			if (strcmp(w, "exprbelow") == 0) {
981 				vpar = &vpar[0];	/* dyn */
982 				vpar2 = &vpar[6];	/* vol */
983 				if (get_bool(p))
984 					val = SL_BELOW;
985 				else
986 					val = SL_ABOVE;
987 				break;
988 			}
989 			break;
990 		case 'v':
991 			if (strcmp(w, "vocalabove") == 0) {	/* compatibility */
992 				vpar = &vpar[5];	/* voc */
993 				if (get_bool(p))
994 					val = SL_ABOVE;
995 				else
996 					val = SL_BELOW;
997 				break;
998 			}
999 			break;
1000 		}
1001 		if (val < 0)
1002 			goto err;
1003 	}
1004 	if (state == ABC_S_TUNE) {
1005 		vpar->f(p_voice, val);
1006 		if (vpar2)
1007 			vpar2->f(p_voice, val);
1008 		return;
1009 	}
1010 	for (i = MAXVOICE, p_voice = voice_tb;	/* global */
1011 	     --i >= 0;
1012 	     p_voice++) {
1013 		vpar->f(p_voice, val);
1014 		if (vpar2)
1015 			vpar2->f(p_voice, val);
1016 	}
1017 	cfmt.posit = voice_tb[0].posit;
1018 	return;
1019 err:
1020 	error(1, NULL, "Bad value %%%%%s %s", w, p);
1021 }
1022 
1023 /* -- parse a format line -- */
interpret_fmt_line(char * w,char * p,int lock)1024 void interpret_fmt_line(char *w,		/* keyword */
1025 			char *p,		/* value */
1026 			int lock)
1027 {
1028 	struct format *fd;
1029 	int i;
1030 	char *q;
1031 	float f;
1032 
1033 	switch (*w) {
1034 	case 'b':
1035 		if (strcmp(w, "barnumbers") == 0)	/* compatibility */
1036 			w = "measurenb";
1037 		break;
1038 	case 'c':
1039 		if (strcmp(w, "comball") == 0) {	/* compatibility */
1040 			cfmt.combinevoices = 2;
1041 			return;
1042 		}
1043 		break;
1044 	case 'f':
1045 		if (strcmp(w, "font") == 0) {
1046 			int fnum, encoding;
1047 			float swfac;
1048 			char fname[80];
1049 
1050 			if (file_initialized > 0
1051 			 && !svg && epsf <= 1) {	/* PS */
1052 				error(1, NULL,
1053 				      "Cannot define a font when the output file is opened");
1054 				return;
1055 			}
1056 			p = get_str(fname, p, sizeof fname);
1057 			swfac = 0;			/* defaults to 1.2 */
1058 			encoding = 0;
1059 			if (*p != '\0') {
1060 				if (isalpha((unsigned char) *p)) {
1061 					encoding = parse_encoding(p);
1062 					while (*p != '\0'
1063 					    && !isspace((unsigned char) *p))
1064 						p++;
1065 					while (isspace((unsigned char) *p))
1066 						p++;
1067 				}
1068 				if (isdigit((unsigned char) *p)) {
1069 					f = strtod(p, &q);
1070 					if (f > 2 || (*q != '\0' && *q != '\0'))
1071 						goto bad;
1072 					swfac = f;
1073 				}
1074 			}
1075 			fnum = get_font(fname, encoding);
1076 			def_font_enc[fnum] = encoding;
1077 			swfac_font[fnum] = swfac;
1078 			used_font[fnum] = 1;
1079 			for (i = FONT_UMAX; i < FONT_MAX; i++) {
1080 				if (cfmt.font_tb[i].fnum == fnum)
1081 					cfmt.font_tb[i].swfac = cfmt.font_tb[i].size
1082 									* swfac;
1083 			}
1084 			return;
1085 		}
1086 		break;
1087 	case 'i':
1088 		if (strcmp(w, "infoname") == 0) {
1089 			if (*p < 'A' || *p > 'Z')
1090 				goto bad;
1091 			set_infoname(p);
1092 			return;
1093 		}
1094 		break;
1095 	case 'm':
1096 		if (strcmp(w, "musiconly") == 0) {	/* compatibility */
1097 			if (get_bool(p))
1098 				cfmt.fields[1] &= ~(1 << ('w' - 'a'));
1099 			else
1100 				cfmt.fields[1] |= (1 << ('w' - 'a'));
1101 			return;
1102 		}
1103 		break;
1104 	case 'p':
1105 		if (strcmp(w, "printparts") == 0) {	/* compatibility */
1106 			if (get_bool(p))
1107 				cfmt.fields[0] |= (1 << ('P' - 'A'));
1108 			else
1109 				cfmt.fields[0] &= ~(1 << ('P' - 'A'));
1110 			return;
1111 		}
1112 		if (strcmp(w, "printtempo") == 0) {	/* compatibility */
1113 			if (get_bool(p))
1114 				cfmt.fields[0] |= (1 << ('Q' - 'A'));
1115 			else
1116 				cfmt.fields[0] &= ~(1 << ('Q' - 'A'));
1117 			return;
1118 		}
1119 		break;
1120 	case 's':
1121 		if (strncmp(w, "setfont-", 8) == 0) {
1122 			i = w[8] - '0';
1123 			if (i < 0 || i >= FONT_UMAX)
1124 				return;
1125 			g_fspc(p, &cfmt.font_tb[i]);
1126 			return;
1127 		}
1128 		if (strcmp(w, "scale") == 0) {
1129 			for (fd = format_tb; fd->name; fd++)
1130 				if (strcmp("pagescale", fd->name) == 0)
1131 					break;
1132 			if (fd->lock)
1133 				return;
1134 			fd->lock = lock;
1135 			f = strtod(p, &q);
1136 			if (*q != '\0' && *q != ' ')
1137 				goto bad;
1138 			cfmt.scale = f / 0.75;		// old -> new scale
1139 			return;
1140 		}
1141 		break;
1142 	case 'w':
1143 		if (strcmp(w, "withxrefs") == 0) {	/* compatibility */
1144 			if (get_bool(p))
1145 				cfmt.fields[0] |= (1 << ('X' - 'A'));
1146 			else
1147 				cfmt.fields[0] &= ~(1 << ('X' - 'A'));
1148 			return;
1149 		}
1150 		if (strcmp(w, "writehistory") == 0) {	/* compatibility */
1151 			struct SYMBOL *s;
1152 			int bool;
1153 			unsigned u;
1154 
1155 			bool = get_bool(p);
1156 			for (s = info['I' - 'A']; s != 0; s = s->next) {
1157 				u = s->text[0] - 'A';
1158 				if (bool)
1159 					cfmt.fields[0] |= (1 << u);
1160 				else
1161 					cfmt.fields[0] &= ~(1 << u);
1162 			}
1163 			return;
1164 		}
1165 		break;
1166 	}
1167 	for (fd = format_tb; fd->name; fd++)
1168 		if (strcmp(w, fd->name) == 0)
1169 			break;
1170 	if (!fd->name)
1171 		return;
1172 
1173 	i = strlen(p);
1174 	if (strcmp(p + i - 5, " lock") == 0) {
1175 		p[i - 5] = '\0';
1176 		lock = 1;
1177 	}
1178 
1179 	if (lock)
1180 		fd->lock = 1;
1181 	else if (fd->lock)
1182 		return;
1183 
1184 	switch (fd->type) {
1185 	case FORMAT_B:
1186 		switch (fd->subtype) {
1187 #ifdef HAVE_PANGO
1188 		case 2:				/* %%pango = 0, 1 or 2 */
1189 			if (*p == '2') {
1190 				cfmt.pango = 2;
1191 				break;
1192 			}
1193 			/* fall thru */
1194 #endif
1195 		default:
1196 		case 0:
1197 		case 3:				/* %%abc2pscompat */
1198 			*((int *) fd->v) = get_bool(p);
1199 			if (fd->subtype == 3) {
1200 				if (cfmt.abc2pscompat)
1201 					deco['M'] = "tenuto";
1202 				else
1203 					deco['M'] = "lowermordent";
1204 			}
1205 			break;
1206 		case 1:	{			/* %%writefields */
1207 			int bool;
1208 			unsigned u;
1209 
1210 			q = p;
1211 			while (*p != '\0' && !isspace((unsigned char) *p))
1212 				p++;
1213 			while (isspace((unsigned char) *p))
1214 				p++;
1215 			bool = get_bool(p);
1216 			while (*q != '\0' && !isspace((unsigned char) *q)) {
1217 				u = *q - 'A';
1218 				if (u < 26) {
1219 					i = 0;
1220 				} else {
1221 					u = *q - 'a';
1222 					if (u < 26)
1223 						i = 1;
1224 					else
1225 						break;	/*fixme: error */
1226 				}
1227 				if (bool)
1228 					cfmt.fields[i] |= (1 << u);
1229 				else
1230 					cfmt.fields[i] &= ~(1 << u);
1231 				q++;
1232 			}
1233 			break;
1234 		    }
1235 		}
1236 		break;
1237 	case FORMAT_I:
1238 		if (fd->subtype == 3) {		/* tuplets */
1239 			unsigned i1, i2, i3, i4 = 0;
1240 
1241 			if (sscanf(p, "%d %d %d %d", &i1, &i2, &i3, &i4) != 4
1242 			 && sscanf(p, "%d %d %d", &i1, &i2, &i3) != 3)
1243 				goto bad;
1244 			if (i1 > 2 || i2 > 2 || i3 > 2 || i4 > 2)
1245 				goto bad;
1246 			cfmt.tuplets = (i1 << 12) | (i2 << 8) | (i3 << 4) | i4;
1247 			break;
1248 		}
1249 		if (fd->subtype == 5) {		/* gracespace */
1250 			unsigned i1, i2, i3;
1251 			float f1, f2, f3;
1252 
1253 			if (sscanf(p, "%f %f %f", &f1, &f2, &f3) != 3
1254 			 || f1 > 25 || f2 > 25 || f3 > 25)
1255 				goto bad;
1256 			i1 = f1 * 10;
1257 			i2 = f2 * 10;
1258 			i3 = f3 * 10;
1259 			cfmt.gracespace = (i1 << 16) | (i2 << 8) | i3;
1260 			break;
1261 		}
1262 		if (fd->subtype == 1			/* splittune */
1263 		  && (strcmp(p, "odd") == 0 || strcmp(p, "even") == 0))
1264 			cfmt.splittune = p[0] == 'e' ? 2 : 3;
1265 		else if (fd->subtype == 2)		/* dblrepbar */
1266 			cfmt.dblrepbar = get_dblrepbar(p);
1267 		else if (fd->subtype == 4 && !isdigit(*p)) /* textoption */
1268 			cfmt.textoption = get_textopt(p);
1269 		else if (isdigit(*p) || *p == '-' || *p == '+')
1270 			sscanf(p, "%d", (int *) fd->v);
1271 		else
1272 			*((int *) fd->v) = get_bool(p);
1273 		if (fd->subtype == 4) {			/* textoption */
1274 			if (cfmt.textoption < 0) {
1275 				cfmt.textoption = 0;
1276 				goto bad;
1277 			}
1278 		}
1279 		break;
1280 	case FORMAT_R:
1281 		f = strtod(p, &q);
1282 		if (*q != '\0' && *q != ' ')
1283 			goto bad;
1284 		switch (fd->subtype) {
1285 		default:
1286 			if (f <= 0)
1287 				goto bad;
1288 			break;
1289 		case 1: {			/* note spacing factor */
1290 			float v2;
1291 
1292 			if (f < 1 || f > 2)
1293 				goto bad;
1294 			i = C_XFLAGS;		/* crotchet index */
1295 			v2 = space_tb[i];
1296 			for ( ; --i >= 0; ) {
1297 				v2 /= f;
1298 				space_tb[i] = v2;
1299 			}
1300 			i = C_XFLAGS;
1301 			v2 = space_tb[i];
1302 			for ( ; ++i < NFLAGS_SZ; ) {
1303 				v2 *= f;
1304 				space_tb[i] = v2;
1305 			}
1306 			break;
1307 		    }
1308 		case 2:				/* maxshrink / stretchlast */
1309 			if (f < 0 || f > 1)
1310 				goto bad;
1311 			break;
1312 		case 3:				/* breaklimit */
1313 			if (f < 0.5 || f > 1)
1314 				goto bad;
1315 			break;
1316 		}
1317 		*((float *) fd->v) = f;
1318 		break;
1319 	case FORMAT_F: {
1320 		int b;
1321 
1322 		g_fspc(p, (struct FONTSPEC *) fd->v);
1323 		b = strstr(p, "box") != NULL;
1324 		switch (fd->subtype) {
1325 		case 1:
1326 			cfmt.partsbox = b;
1327 			break;
1328 		case 2:
1329 			cfmt.measurebox = b;
1330 			break;
1331 		case 3:
1332 			cfmt.gchordbox = b;
1333 			break;
1334 		}
1335 		break;
1336 	    }
1337 	case FORMAT_U:
1338 		*((float *) fd->v) = scan_u(p, fd->subtype);
1339 		switch (fd->subtype) {
1340 		case 2:					/* staffwidth */
1341 			f = (cfmt.landscape ? cfmt.pageheight : cfmt.pagewidth)
1342 					- staffwidth - cfmt.leftmargin;
1343 			if (f < 0)
1344 				error(1, NULL, "'staffwidth' too big\n");
1345 			else
1346 				cfmt.rightmargin = f;
1347 			break;
1348 		}
1349 		break;
1350 	case FORMAT_S:
1351 		i = strlen(p) + 1;
1352 		*((char **) fd->v) = getarena(i);
1353 		if (*p == '"')
1354 			get_str(*((char **) fd->v), p, i);
1355 		else
1356 			strcpy(*((char **) fd->v), p);
1357 		if (fd->subtype == 1) {			// musicfont
1358 			// (no control)
1359 			svg_font_switch();
1360 		}
1361 		break;
1362 	}
1363 	return;
1364 bad:
1365 	error(1, NULL, "Bad value '%s' for '%s' - ignored", p, w);
1366 }
1367 
1368 /* -- lock a format -- */
lock_fmt(void * fmt)1369 void lock_fmt(void *fmt)
1370 {
1371 	struct format *fd;
1372 
1373 	for (fd = format_tb; fd->name; fd++)
1374 		if (fd->v == fmt)
1375 			break;
1376 	if (fd->name == 0)
1377 		return;
1378 	fd->lock = 1;
1379 }
1380 
1381 /* -- start a new font -- */
set_font(int ft)1382 void set_font(int ft)
1383 {
1384 	int fnum;
1385 	struct FONTSPEC *f, *f2;
1386 
1387 	if (ft == outft)
1388 		return;
1389 	f = &cfmt.font_tb[ft];
1390 	if (outft >= 0) {
1391 		f2 = &cfmt.font_tb[outft];
1392 		outft = ft;
1393 		fnum = f->fnum;
1394 		if (fnum == f2->fnum && f->size == f2->size)
1395 			return;
1396 	} else {
1397 		outft = ft;
1398 		fnum = f->fnum;
1399 	}
1400 	if (!used_font[fnum]
1401 	 && epsf <= 1 && !svg) {	/* (not usefull for svg output) */
1402 		if (file_initialized <= 0) {
1403 			used_font[fnum] = 1;
1404 		} else {
1405 			error(1, NULL,
1406 			      "Font '%s' not predefined; using first in list",
1407 			      fontnames[fnum]);
1408 			fnum = 0;
1409 		}
1410 	}
1411 	if (f->size == 0) {
1412 		error(0, NULL, "Font '%s' with a null size - set to 8",
1413 		      fontnames[fnum]);
1414 		f->size = 8;
1415 	}
1416 	a2b("%.1f F%d ", f->size, fnum);
1417 }
1418 
1419 /* -- get the encoding of a font -- */
get_font_encoding(int ft)1420 int get_font_encoding(int ft)
1421 {
1422 	return font_enc[ft];
1423 }
1424