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