Added hint about removed "freepascal" to a file which is supposed to have that inform...
[AROS-Contrib.git] / MultiMedia / abcm2ps / format.c
blobf2484a8b29a8b74d8a32016b0233bd085eefa63f
1 /*
2 * Formatting functions.
4 * This file is part of abcm2ps.
6 * Copyright (C) 1998-2008 Jean-François Moine
7 * Adapted from abc2ps, Copyright (C) 1996,1997 Michael Methfessel
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.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <time.h>
28 #include <ctype.h>
30 #include "abcparse.h"
31 #include "abc2ps.h"
33 struct FORMAT cfmt; /* current format for output */
35 char font_enc[MAXFONTS]; /* font encoding */
36 static char def_font_enc[MAXFONTS]; /* default font encoding */
37 static char *fontnames[MAXFONTS]; /* list of font names */
38 static char used_font[MAXFONTS]; /* used fonts */
39 static int nfontnames;
40 static float staffwidth;
42 /* format table */
43 static struct format {
44 char *name;
45 void *v;
46 char type;
47 #define FORMAT_I 0 /* int */
48 #define FORMAT_R 1 /* float */
49 #define FORMAT_F 2 /* font spec */
50 #define FORMAT_U 3 /* float with unit */
51 #define FORMAT_B 4 /* boolean */
52 #define FORMAT_S 5 /* string */
53 char subtype; /* special cases - see code */
54 short lock;
55 } format_tb[] = {
56 {"abc2pscompat", &cfmt.abc2pscompat, FORMAT_B, 0},
57 {"alignbars", &cfmt.alignbars, FORMAT_I, 0},
58 {"aligncomposer", &cfmt.aligncomposer, FORMAT_I, 0},
59 {"autoclef", &cfmt.autoclef, FORMAT_B, 0},
60 {"annotationfont", &cfmt.font_tb[ANNOTATIONFONT], FORMAT_F, 0},
61 {"barsperstaff", &cfmt.barsperstaff, FORMAT_I, 0},
62 {"botmargin", &cfmt.botmargin, FORMAT_U, 0},
63 {"breakoneoln", &cfmt.breakoneoln, FORMAT_B, 0},
64 {"bstemdown", &cfmt.bstemdown, FORMAT_B, 0},
65 {"combinevoices", &cfmt.combinevoices, FORMAT_B, 0},
66 {"comball", &cfmt.comball, FORMAT_B, 0},
67 {"composerfont", &cfmt.font_tb[COMPOSERFONT], FORMAT_F, 0},
68 {"composerspace", &cfmt.composerspace, FORMAT_U, 0},
69 {"contbarnb", &cfmt.contbarnb, FORMAT_B, 0},
70 {"continueall", &cfmt.continueall, FORMAT_B, 0},
71 {"dateformat", &cfmt.dateformat, FORMAT_S, 0},
72 {"dynalign", &cfmt.dynalign, FORMAT_B, 0},
73 {"encoding", &cfmt.encoding, FORMAT_I, 1},
74 {"exprabove", &cfmt.exprabove, FORMAT_B, 0},
75 {"exprbelow", &cfmt.exprbelow, FORMAT_B, 0},
76 {"footer", &cfmt.footer, FORMAT_S, 0},
77 {"footerfont", &cfmt.font_tb[FOOTERFONT], FORMAT_F, 0},
78 {"freegchord", &cfmt.freegchord, FORMAT_B, 0},
79 {"flatbeams", &cfmt.flatbeams, FORMAT_B, 0},
80 {"gchordbox", &cfmt.gchordbox, FORMAT_B, 0},
81 {"gchordfont", &cfmt.font_tb[GCHORDFONT], FORMAT_F, 3},
82 {"graceslurs", &cfmt.graceslurs, FORMAT_B, 0},
83 {"gracespace", &cfmt.gracespace, FORMAT_I, 5},
84 {"header", &cfmt.header, FORMAT_S, 0},
85 {"headerfont", &cfmt.font_tb[HEADERFONT], FORMAT_F, 0},
86 {"historyfont", &cfmt.font_tb[HISTORYFONT], FORMAT_F, 0},
87 {"hyphencont", &cfmt.hyphencont, FORMAT_B, 0},
88 {"indent", &cfmt.indent, FORMAT_U, 0},
89 {"infofont", &cfmt.font_tb[INFOFONT], FORMAT_F, 0},
90 {"infoline", &cfmt.infoline, FORMAT_B, 0},
91 {"infospace", &cfmt.infospace, FORMAT_U, 0},
92 {"landscape", &cfmt.landscape, FORMAT_B, 0},
93 {"leftmargin", &cfmt.leftmargin, FORMAT_U, 0},
94 {"lineskipfac", &cfmt.lineskipfac, FORMAT_R, 0},
95 {"maxshrink", &cfmt.maxshrink, FORMAT_R, 0},
96 {"maxstaffsep", &cfmt.maxstaffsep, FORMAT_U, 0},
97 {"maxsysstaffsep", &cfmt.maxsysstaffsep, FORMAT_U, 0},
98 {"measurebox", &cfmt.measurebox, FORMAT_B, 0},
99 {"measurefirst", &cfmt.measurefirst, FORMAT_I, 2},
100 {"measurefont", &cfmt.font_tb[MEASUREFONT], FORMAT_F, 2},
101 {"measurenb", &cfmt.measurenb, FORMAT_I, 0},
102 {"musiconly", &cfmt.musiconly, FORMAT_B, 0},
103 {"musicspace", &cfmt.musicspace, FORMAT_U, 0},
104 {"notespacingfactor", &cfmt.notespacingfactor, FORMAT_R, 1},
105 {"oneperpage", &cfmt.oneperpage, FORMAT_B, 0},
106 {"pageheight", &cfmt.pageheight, FORMAT_U, 0},
107 {"pagewidth", &cfmt.pagewidth, FORMAT_U, 0},
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 {"printparts", &cfmt.printparts, FORMAT_B, 0},
113 {"printtempo", &cfmt.printtempo, FORMAT_B, 0},
114 {"repeatfont", &cfmt.font_tb[REPEATFONT], FORMAT_F, 0},
115 {"rightmargin", &cfmt.rightmargin, FORMAT_U, 0},
116 {"scale", &cfmt.scale, FORMAT_R, 0},
117 {"setdefl", &cfmt.setdefl, FORMAT_B, 0},
118 {"setfont-1", &cfmt.font_tb[1], FORMAT_F, 0},
119 {"setfont-2", &cfmt.font_tb[2], FORMAT_F, 0},
120 {"setfont-3", &cfmt.font_tb[3], FORMAT_F, 0},
121 {"setfont-4", &cfmt.font_tb[4], FORMAT_F, 0},
122 #if FONT_UMAX!=5
123 # error Bad number of user fonts
124 #endif
125 {"shifthnote", &cfmt.shiftunisson, FORMAT_B, 0}, /*to remove*/
126 {"shiftunisson", &cfmt.shiftunisson, FORMAT_B, 0},
127 {"slurheight", &cfmt.slurheight, FORMAT_R, 0},
128 {"splittune", &cfmt.splittune, FORMAT_B, 0},
129 {"squarebreve", &cfmt.squarebreve, FORMAT_B, 0},
130 {"staffnonote", &cfmt.staffnonote, FORMAT_B, 0},
131 {"staffsep", &cfmt.staffsep, FORMAT_U, 0},
132 {"staffwidth", &staffwidth, FORMAT_U, 1},
133 {"stemheight", &cfmt.stemheight, FORMAT_R, 0},
134 {"straightflags", &cfmt.straightflags, FORMAT_B, 0},
135 {"stretchlast", &cfmt.stretchlast, FORMAT_B, 0},
136 {"stretchstaff", &cfmt.stretchstaff, FORMAT_B, 0},
137 {"subtitlefont", &cfmt.font_tb[SUBTITLEFONT], FORMAT_F, 0},
138 {"subtitlespace", &cfmt.subtitlespace, FORMAT_U, 0},
139 {"sysstaffsep", &cfmt.sysstaffsep, FORMAT_U, 0},
140 {"tempofont", &cfmt.font_tb[TEMPOFONT], FORMAT_F, 0},
141 {"textfont", &cfmt.font_tb[TEXTFONT], FORMAT_F, 0},
142 {"textoption", &cfmt.textoption, FORMAT_I, 4},
143 {"textspace", &cfmt.textspace, FORMAT_U, 0},
144 {"titlecaps", &cfmt.titlecaps, FORMAT_B, 0},
145 {"titlefont", &cfmt.font_tb[TITLEFONT], FORMAT_F, 0},
146 {"titleformat", &cfmt.titleformat, FORMAT_S, 0},
147 {"titleleft", &cfmt.titleleft, FORMAT_B, 0},
148 {"titlespace", &cfmt.titlespace, FORMAT_U, 0},
149 {"titletrim", &cfmt.titletrim, FORMAT_B, 0},
150 {"timewarn", &cfmt.timewarn, FORMAT_B, 0},
151 {"topmargin", &cfmt.topmargin, FORMAT_U, 0},
152 {"topspace", &cfmt.topspace, FORMAT_U, 0},
153 {"tuplets", &cfmt.tuplets, FORMAT_I, 3},
154 {"vocalabove", &cfmt.vocalabove, FORMAT_B, 0},
155 {"vocalfont", &cfmt.font_tb[VOCALFONT], FORMAT_F, 0},
156 {"vocalspace", &cfmt.vocalspace, FORMAT_U, 0},
157 {"voicefont", &cfmt.font_tb[VOICEFONT], FORMAT_F, 0},
158 {"withxrefs", &cfmt.withxrefs, FORMAT_B, 0},
159 {"wordsfont", &cfmt.font_tb[WORDSFONT], FORMAT_F, 0},
160 {"wordsspace", &cfmt.wordsspace, FORMAT_U, 0},
161 {"writehistory", &cfmt.writehistory, FORMAT_B, 0},
162 {0, 0, 0, 0} /* end of table */
165 static char *enc_name[20] = {
166 "us-ascii", /* 0 */
167 "iso-8859-1", /* 1 */
168 "iso-8859-2", /* 2 */
169 "iso-8859-3", /* 3 */
170 "iso-8859-4", /* 4 */
171 "iso-8859-9", /* 5 (Latin5) */
172 "iso-8859-10", /* 6 (Latin6) */
173 "native", /* 7 = ENC_NATIVE */
174 #if 0
175 "utf-8", /* 8 */
176 #endif
179 /* -- search a font and add it if not yet defined -- */
180 static int get_font(char *fname, int encoding)
182 int fnum;
184 /* get or set the default encoding */
185 for (fnum = nfontnames; --fnum >= 0; )
186 if (strcmp(fname, fontnames[fnum]) == 0) {
187 if (encoding < 0)
188 encoding = def_font_enc[fnum];
189 if (encoding == font_enc[fnum])
190 return fnum; /* font found */
192 for ( ; --fnum >= 0; )
193 if (strcmp(fname, fontnames[fnum]) == 0
194 && encoding == font_enc[fnum])
195 return fnum;
197 /* add the font */
198 if (nfontnames >= MAXFONTS) {
199 error(1, 0, "Too many fonts");
200 return 0;
202 if (file_initialized)
203 error(1, 0,
204 "Cannot have a new font when the output file is opened");
205 fnum = nfontnames++;
206 fontnames[fnum] = strdup(fname);
207 if (encoding < 0)
208 encoding = cfmt.encoding;
209 font_enc[fnum] = encoding;
210 return fnum;
213 /* -- set a dynamic font -- */
214 static int dfont_set(struct FONTSPEC *f)
216 int i;
218 for (i = FONT_DYN; i < cfmt.ndfont; i++) {
219 if (cfmt.font_tb[i].fnum == f->fnum
220 && cfmt.font_tb[i].size == f->size)
221 return i;
223 if (i >= FONT_MAX - 1) {
224 error(1, 0, "Too many dynamic fonts");
225 return FONT_MAX - 1;
227 memcpy(&cfmt.font_tb[i], f, sizeof cfmt.font_tb[0]);
228 cfmt.ndfont = i + 1;
229 return i;
232 /* -- define a font -- */
233 static void fontspec(struct FONTSPEC *f,
234 char *name,
235 int encoding,
236 float size)
238 if (name != 0)
239 f->fnum = get_font(name, encoding);
240 else name = fontnames[f->fnum];
241 f->size = size;
242 f->swfac = size;
243 if (strncmp(name, "Times", 5) == 0) {
244 if (strcmp(name, "Times-Bold") == 0)
245 f->swfac *= 1.05;
246 } else if (strcmp(name, "Helvetica-Bold") == 0)
247 f->swfac *= 1.15;
248 else if (strncmp(name, "Helvetica", 9) == 0
249 || strncmp(name, "Palatino", 8) == 0)
250 f->swfac *= 1.10;
251 else if (strncmp(name, "Courier", 7) == 0)
252 f->swfac *= 1.35;
253 else f->swfac *= 1.2; /* unknown font */
254 if (f == &cfmt.font_tb[GCHORDFONT])
255 cfmt.gcf = dfont_set(f);
256 else if (f == &cfmt.font_tb[ANNOTATIONFONT])
257 cfmt.anf = dfont_set(f);
258 else if (f == &cfmt.font_tb[VOCALFONT])
259 cfmt.vof = dfont_set(f);
262 /* -- output the encodings -- */
263 void define_encodings(void)
265 int i, enc;
267 enc = 0;
268 for (i = 0; i < nfontnames; i++) {
269 if (used_font[i])
270 enc |= 1 << font_enc[i];
272 for (i = 0; ; i++) {
273 if (enc == 0)
274 break;
275 if (enc & 1)
276 define_encoding(i, enc_name[i]);
277 enc >>= 1;
281 /* -- output the font definitions with their encodings -- */
282 void define_fonts(void)
284 int i;
286 for (i = 0; i < nfontnames; i++) {
287 if (used_font[i])
288 define_font(fontnames[i], i, font_enc[i]);
292 /* -- mark the used fonts -- */
293 void make_font_list(void)
295 struct FORMAT *f;
297 f = &cfmt;
298 used_font[f->font_tb[ANNOTATIONFONT].fnum] = 1;
299 used_font[f->font_tb[COMPOSERFONT].fnum] = 1;
300 used_font[f->font_tb[FOOTERFONT].fnum] = 1;
301 used_font[f->font_tb[GCHORDFONT].fnum] = 1;
302 used_font[f->font_tb[HEADERFONT].fnum] = 1;
303 used_font[f->font_tb[HISTORYFONT].fnum] = 1;
304 used_font[f->font_tb[INFOFONT].fnum] = 1;
305 used_font[f->font_tb[MEASUREFONT].fnum] = 1;
306 used_font[f->font_tb[PARTSFONT].fnum] = 1;
307 used_font[f->font_tb[REPEATFONT].fnum] = 1;
308 used_font[f->font_tb[SUBTITLEFONT].fnum] = 1;
309 used_font[f->font_tb[TEMPOFONT].fnum] = 1;
310 used_font[f->font_tb[TEXTFONT].fnum] = 1;
311 used_font[f->font_tb[TITLEFONT].fnum] = 1;
312 used_font[f->font_tb[VOCALFONT].fnum] = 1;
313 used_font[f->font_tb[VOICEFONT].fnum] = 1;
314 used_font[f->font_tb[WORDSFONT].fnum] = 1;
317 /* -- set the name of an information header type -- */
318 /* the argument is
319 * <letter> [ <possibly quoted string> ]
320 * this information is kept in the 'I' information */
321 static void set_infoname(char *p)
323 struct SYMBOL *s, *prev;
324 int old_lvl;
326 if (*p == 'I')
327 return;
328 s = info['I' - 'A'];
329 prev = 0;
330 while (s != 0) {
331 if (s->as.text[0] == *p)
332 break;
333 prev = s;
334 s = s->next;
336 if (p[1] == '\0') { /* if delete */
337 if (s != 0) {
338 if ((prev->next = s->next) != 0)
339 prev->next->prev = prev;
341 return;
343 old_lvl = lvlarena(0);
344 if (s == 0) {
345 s = (struct SYMBOL *) getarena(sizeof *s);
346 memset(s, 0, sizeof *s);
347 if (prev == 0)
348 info['I' - 'A'] = s;
349 else {
350 prev->next = s;
351 s->prev = prev;
354 s->as.text = (char *) getarena(strlen(p) + 1);
355 strcpy(s->as.text, p);
356 lvlarena(old_lvl);
359 /* -- set the default format -- */
360 void set_format(void)
362 struct FORMAT *f;
364 f = &cfmt;
365 memset(f, 0, sizeof *f);
366 f->pageheight = PAGEHEIGHT;
367 f->pagewidth = PAGEWIDTH;
368 f->leftmargin = MARGIN;
369 f->rightmargin = MARGIN;
370 f->topmargin = 1.0 CM;
371 f->botmargin = 1.0 CM;
372 f->topspace = 0.8 CM;
373 f->titlespace = 0.2 CM;
374 f->subtitlespace = 0.1 CM;
375 f->composerspace = 0.2 CM;
376 f->musicspace = 0.2 CM;
377 f->partsspace = 0.3 CM;
378 f->staffsep = 46.0 PT;
379 f->sysstaffsep = 34.0 PT;
380 f->maxstaffsep = 2000.0 PT;
381 f->maxsysstaffsep = 2000.0 PT;
382 f->vocalspace = 23.0 PT;
383 f->textspace = 0.5 CM;
384 f->scale = 0.75;
385 f->slurheight = 1.0;
386 f->maxshrink = 0.65;
387 f->stretchstaff = 1;
388 f->graceslurs = 1;
389 f->lineskipfac = 1.1;
390 f->parskipfac = 0.4;
391 f->measurenb = -1;
392 f->measurefirst = 1;
393 f->autoclef = 1;
394 f->breakoneoln = 1;
395 f->dynalign = 1;
396 f->printparts = 1;
397 f->printtempo = 1;
398 f->staffnonote = 1;
399 f->titletrim = 1;
400 f->aligncomposer = A_RIGHT;
401 f->notespacingfactor = 1.414;
402 f->stemheight = STEM;
403 f->dateformat = strdup("\\%b \\%e, \\%Y \\%H:\\%M");
404 f->gracespace = (65 << 16) | (80 << 8) | 120; /* left-inside-right - unit 1/10 pt */
405 f->textoption = T_LEFT;
406 f->ndfont = FONT_DYN;
407 fontspec(&f->font_tb[ANNOTATIONFONT], "Helvetica", 0, 12.0);
408 fontspec(&f->font_tb[COMPOSERFONT], "Times-Italic", 0, 14.0);
409 fontspec(&f->font_tb[FOOTERFONT], "Times-Roman", 0, 12.0); /* not scaled */
410 fontspec(&f->font_tb[GCHORDFONT], "Helvetica", 0, 12.0);
411 fontspec(&f->font_tb[HEADERFONT], "Times-Roman", 0, 12.0); /* not scaled */
412 fontspec(&f->font_tb[HISTORYFONT], "Times-Roman", 0, 16.0);
413 fontspec(&f->font_tb[INFOFONT], "Times-Italic", 0, 14.0); /* same as composer by default */
414 fontspec(&f->font_tb[MEASUREFONT], "Times-Italic", 0, 14.0);
415 fontspec(&f->font_tb[PARTSFONT], "Times-Roman", 0, 15.0);
416 fontspec(&f->font_tb[REPEATFONT], "Times-Roman", 0, 13.0);
417 fontspec(&f->font_tb[SUBTITLEFONT], "Times-Roman", 0, 16.0);
418 fontspec(&f->font_tb[TEMPOFONT], "Times-Bold", 0, 15.0);
419 fontspec(&f->font_tb[TEXTFONT], "Times-Roman", 0, 16.0);
420 fontspec(&f->font_tb[TITLEFONT], "Times-Roman", 0, 20.0);
421 fontspec(&f->font_tb[VOCALFONT], "Times-Bold", 0, 13.0);
422 fontspec(&f->font_tb[VOICEFONT], "Times-Bold", 0, 13.0);
423 fontspec(&f->font_tb[WORDSFONT], "Times-Roman", 0, 16.0);
424 set_infoname("R \"Rhythm: \"");
425 set_infoname("B \"Book: \"");
426 set_infoname("S \"Source: \"");
427 set_infoname("D \"Discography: \"");
428 set_infoname("N \"Notes: \"");
429 set_infoname("Z \"Transcription: \"");
430 set_infoname("H \"History: \"");
433 /* -- print the current format -- */
434 void print_format(void)
436 struct format *fd;
437 static char yn[2][5]={"no","yes"};
439 for (fd = format_tb; fd->name; fd++) {
440 printf(" %-13s ", fd->name);
441 switch (fd->type) {
442 case FORMAT_I:
443 switch (fd->subtype) {
444 default:
445 printf("%d\n", *((int *) fd->v));
446 break;
447 case 1: /* encoding */
448 printf("%s\n", enc_name[*((int *) fd->v)]);
449 break;
450 case 3: /* tuplets */
451 printf("%d %d %d\n",
452 cfmt.tuplets >> 8,
453 (cfmt.tuplets >> 4) & 0x0f,
454 cfmt.tuplets & 0x0f);
455 break;
456 case 5: /* gracespace */
457 printf("%d.%d %d.%d %d.%d\n",
458 (cfmt.gracespace >> 16) / 10,
459 (cfmt.gracespace >> 16) % 10,
460 ((cfmt.gracespace >> 8) & 0xff) / 10,
461 ((cfmt.gracespace >> 8) & 0xff) % 10,
462 (cfmt.gracespace & 0xff) / 10,
463 (cfmt.gracespace & 0xff) % 10);
464 break;
466 break;
467 case FORMAT_R:
468 printf("%.2f\n", *((float *) fd->v));
469 break;
470 case FORMAT_F: {
471 struct FONTSPEC *s;
473 s = (struct FONTSPEC *) fd->v;
474 printf("%s", fontnames[s->fnum]);
475 if (font_enc[s->fnum] != cfmt.encoding)
476 printf(" %s",
477 enc_name[(unsigned) font_enc[s->fnum]]);
478 printf(" %.1f", s->size);
479 if ((fd->subtype == 1 && cfmt.partsbox)
480 || (fd->subtype == 2 && cfmt.measurebox)
481 || (fd->subtype == 3 && cfmt.gchordbox))
482 printf(" box");
483 printf("\n");
484 break;
486 case FORMAT_U:
487 if (fd->subtype == 0)
488 printf("%.2fcm\n", *((float *) fd->v) / (1 CM));
489 else printf("%.2fcm\n",
490 (cfmt.pagewidth
491 - cfmt.leftmargin
492 - cfmt.rightmargin)
493 / (1 CM));
494 break;
495 case FORMAT_B:
496 printf("%s\n", yn[*((int *) fd->v)]);
497 break;
498 case FORMAT_S:
499 printf("\"%s\"\n", *((char **) fd->v) != 0 ? *((char **) fd->v) : "");
500 break;
505 /* -- get an encoding -- */
506 static int get_encoding(char *p)
508 int l;
509 char **e;
511 l = 0;
512 while (p[l] != '\0' && !isspace((unsigned char) p[l]))
513 l++;
514 if (strncasecmp(p, "ASCII", l) == 0) /* backward compatibility */
515 return 0;
516 e = enc_name;
517 for (;;) {
518 if (strncmp(p, *e, l) == 0)
519 break;
520 e++;
521 if (*e == 0
522 || e >= &enc_name[sizeof enc_name]) {
523 if (e >= &enc_name[sizeof enc_name - 1]) {
524 error(1, 0, "Too many encodings");
525 return 0;
527 *e = (char *) malloc(l + 1);
528 strncpy(*e, p, l);
529 (*e)[l] = '\0';
532 return e - enc_name;
535 /* -- get the option for text -- */
536 int get_textopt(char *p)
538 int option;
540 option = T_LEFT;
541 if (*p == '\0'
542 || strncmp(p, "obeylines", 9) == 0)
544 else if (strncmp(p, "align", 5) == 0
545 || strncmp(p, "justify", 7) == 0)
546 option = T_JUSTIFY;
547 else if (strncmp(p, "ragged", 6) == 0
548 || strncmp(p, "fill", 4) == 0)
549 option = T_FILL;
550 else if (strncmp(p, "center", 6) == 0)
551 option = T_CENTER;
552 else if (strncmp(p, "skip", 4) == 0)
553 option = T_SKIP;
554 else if (strncmp(p, "right", 5) == 0)
555 option = T_RIGHT;
556 else option = -1;
557 return option;
560 /* -- get a boolean value -- */
561 static int g_logv(char *p)
563 switch (*p) {
564 case 0:
565 case '1':
566 case 'y':
567 case 'Y':
568 case 't':
569 case 'T':
570 return 1;
571 case '0':
572 case 'n':
573 case 'N':
574 case 'f':
575 case 'F':
576 break;
577 default:
578 fprintf(stderr,
579 "++++ Unknown logical '%s' - false assumed\n", p);
580 break;
582 return 0;
585 /* -- get a float variable, no units -- */
586 static float g_fltv(char *p)
588 return atof(p);
591 /* -- get a font specifier -- */
592 static void g_fspc(char *p,
593 struct FONTSPEC *f)
595 char fname[80];
596 int encoding;
597 float fsize;
599 p = get_str(fname, p, sizeof fname);
600 if (!isdigit((unsigned char) *p)) {
601 if (*p == '*')
602 encoding = font_enc[f->fnum];
603 else encoding = get_encoding(p);
604 while (*p != '\0' && !isspace((unsigned char) *p))
605 p++;
606 while (isspace((unsigned char) *p))
607 p++;
608 } else encoding = -1;
609 fsize = *p != '\0' && *p != '*' ? g_fltv(p) : f->size;
610 fontspec(f,
611 strcmp(fname, "*") != 0 ? fname : 0,
612 encoding,
613 fsize);
614 if (!file_initialized)
615 used_font[f->fnum] = 1;
616 if (f - cfmt.font_tb == outft)
617 outft = -1;
620 /* -- parse a 'tablature' definition -- */
621 /* %%tablature
622 * [#<nunmber (1..MAXTBLT)>]
623 * [pitch=<instrument pitch (<note> # | b)>]
624 * [[<head width>]
625 * <height above>]
626 * <height under>
627 * <head function>
628 * <note function>
629 * [<bar function>]
631 struct tblt_s *tblt_parse(char *p)
633 struct tblt_s *tblt;
634 int n;
635 char *q;
636 static char notes_tb[14] = "CDEFGABcdefgab";
637 static char pitch_tb[14] = {60, 62, 64, 65, 67, 69, 71,
638 72, 74, 76, 77, 79, 81, 83};
640 /* number */
641 if (*p == '#') {
642 p++;
643 n = *p++ - '0' - 1;
644 if ((unsigned) n >= MAXTBLT
645 || (*p != '\0' && *p != ' ')) {
646 error(1, 0, "Invalid number in %%%%tablature");
647 return 0;
649 if (*p == '\0')
650 return tblts[n];
651 while (isspace((unsigned char) *p))
652 p++;
653 } else n = -1;
655 /* pitch */
656 tblt = malloc(sizeof *tblt);
657 memset(tblt, 0, sizeof *tblt);
658 if (strncmp(p, "pitch=", 6) == 0) {
659 p += 6;
660 if (*p == '^' || *p == '_') {
661 if (*p == '^') {
662 tblt->pitch++;
663 tblt->instr[1] = '#';
664 } else {
665 tblt->pitch--;
666 tblt->instr[1] = 'b';
668 p++;
670 if (*p == '\0' || (q = strchr(notes_tb, *p)) == 0) {
671 error(1, 0, "Invalid pitch in %%%%tablature");
672 return 0;
674 tblt->pitch += pitch_tb[q - notes_tb];
675 tblt->instr[0] = toupper(*p++);
676 while (*p == '\'' || *p == ',') {
677 if (*p++ == '\'')
678 tblt->pitch += 12;
679 else tblt->pitch -= 12;
681 if (*p == '#' || *p == 'b') {
682 if (*p == '#')
683 tblt->pitch++;
684 else tblt->pitch--;
685 tblt->instr[1] = *p++;
687 while (*p == '\'' || *p == ',') {
688 if (*p++ == '\'')
689 tblt->pitch += 12;
690 else tblt->pitch -= 12;
692 while (isspace((unsigned char) *p))
693 p++;
696 /* width and heights */
697 if (!isdigit(*p)) {
698 error(1, 0, "Invalid width/height in %%%%tablature");
699 return 0;
701 tblt->hu = scan_u(p);
702 while (*p != '\0' && !isspace((unsigned char) *p))
703 p++;
704 while (isspace((unsigned char) *p))
705 p++;
706 if (isdigit(*p)) {
707 tblt->ha = tblt->hu;
708 tblt->hu = scan_u(p);
709 while (*p != '\0' && !isspace((unsigned char) *p))
710 p++;
711 while (isspace((unsigned char) *p))
712 p++;
713 if (isdigit(*p)) {
714 tblt->wh = tblt->ha;
715 tblt->ha = tblt->hu;
716 tblt->hu = scan_u(p);
717 while (*p != '\0' && !isspace((unsigned char) *p))
718 p++;
719 while (isspace((unsigned char) *p))
720 p++;
723 if (*p == '\0')
724 goto err;
726 /* PS functions */
727 p = strdup(p);
728 tblt->head = p;
729 while (*p != '\0' && !isspace((unsigned char) *p))
730 p++;
731 if (*p == '\0')
732 goto err;
733 *p++ = '\0';
734 while (isspace((unsigned char) *p))
735 p++;
736 tblt->note = p;
737 while (*p != '\0' && !isspace((unsigned char) *p))
738 p++;
739 if (*p != '\0') {
740 *p++ = '\0';
741 while (isspace((unsigned char) *p))
742 p++;
743 tblt->bar = p;
744 while (*p != '\0' && !isspace((unsigned char) *p))
745 p++;
746 if (*p != '\0')
747 goto err;
750 /* memorize the definition */
751 if (n >= 0)
752 tblts[n] = tblt;
753 return tblt;
754 err:
755 error(1, 0, "Wrong values in %%%%tablature");
756 return 0;
759 /* -- parse a format line -- */
760 void interpret_fmt_line(char *w, /* keyword */
761 char *p, /* argument */
762 int lock)
764 struct format *fd;
766 switch (w[0]) {
767 case 'b':
768 if (strcmp(w, "barnumbers") == 0)
769 w = "measurenb";
770 break;
771 case 'd':
772 if (strcmp(w, "deco") == 0) {
773 deco_add(p);
774 return;
776 break;
777 case 'f':
778 if (strcmp(w, "font") == 0) {
779 int fnum, encoding;
780 char fname[80];
782 p = get_str(fname, p, sizeof fname);
783 if (*p == '\0')
784 encoding = cfmt.encoding;
785 else encoding = get_encoding(p);
786 fnum = get_font(fname, encoding);
787 def_font_enc[fnum] = encoding;
788 used_font[fnum] = 1;
789 return;
791 if (strcmp(w, "format") == 0) {
792 if (read_fmt_file(p) < 0)
793 error(1, 0, "No such format file '%s'", p);
794 return;
796 break;
797 case 'i':
798 if (strcmp(w, "infoname") == 0) {
799 if (*p < 'A' || *p > 'Z') {
800 error(1, 0, "Bad info type '%c' in %%%%infoname",
801 *p);
802 return;
804 set_infoname(p);
805 return;
807 break;
808 case 'p':
809 if (strcmp(w, "postscript") == 0) {
810 if (!file_initialized)
811 user_ps_add(p);
812 else
813 PUT1("%s\n", p);
814 return;
816 break;
817 case 't':
818 if (strcmp(w, "tablature") == 0) {
819 tblt_parse(p);
820 return;
822 break;
824 for (fd = format_tb; fd->name; fd++)
825 if (strcmp(w, fd->name) == 0)
826 break;
827 if (fd->name == 0)
828 return;
829 if (fd->lock && !lock)
830 return;
831 fd->lock |= lock;
832 switch (fd->type) {
833 case FORMAT_I:
834 if (fd->subtype == 3) { /* tuplets */
835 unsigned i1, i2, i3;
837 if (sscanf(p, "%d %d %d", &i1, &i2, &i3) != 3
838 || i1 > 2 || i2 > 2 || i3 > 2) {
839 error(1, 0,
840 "Bad 'tuplets' values '%s' - ignored",
842 return;
844 cfmt.tuplets = (i1 << 8) | (i2 << 4) | i3;
845 break;
847 if (fd->subtype == 5) { /* gracespace */
848 unsigned i1, i2, i3;
849 float f1, f2, f3;
851 if (sscanf(p, "%f %f %f", &f1, &f2, &f3) != 3
852 || f1 > 256 || f2 > 256 || f3 > 256) {
853 error(1, 0,
854 "Bad 'gracespace' values '%s' - ignored",
856 return;
858 i1 = f2 * 10;
859 i2 = f2 * 10;
860 i3 = f3 * 10;
861 cfmt.gracespace = (i1 << 16) | (i2 << 8) | i3;
862 break;
864 if (fd->subtype == 1 && !isdigit(*p)) /* 'encoding' */
865 cfmt.encoding = get_encoding(p);
866 else if (fd->subtype == 4 && !isdigit(*p)) /* 'textoption' */
867 cfmt.textoption = get_textopt(p);
868 else sscanf(p, "%d", (int *) fd->v);
869 switch (fd->subtype) {
870 case 1: /* 'encoding' */
871 if (isdigit(*p)
872 && (unsigned) cfmt.encoding > MAXENC) {
873 error(1, 0,
874 "Bad encoding value %d - reset to 0",
875 cfmt.encoding);
876 cfmt.encoding = 0;
877 } else {
878 int i;
880 for (i = 0; i < nfontnames; i++) {
881 if (font_enc[i] == 0)
882 def_font_enc[i] = font_enc[i]
883 = cfmt.encoding;
886 break;
887 case 2:
888 nbar = nbar_rep = cfmt.measurefirst;
889 break;
890 case 4: /* 'textoption' */
891 if (cfmt.textoption < 0) {
892 error(1, 0,
893 "Bad 'textoption' value '%s'",
895 cfmt.textoption = T_LEFT;
897 break;
899 break;
900 case FORMAT_R:
901 *((float *) fd->v) = g_fltv(p);
902 if (fd->subtype == 1) { /* note spacing factor */
903 int i;
904 float w;
906 if (cfmt.notespacingfactor <= 0) {
907 fprintf(stderr,
908 "Bad value for 'notespacingfactor'\n");
909 cfmt.notespacingfactor = 1;
910 break;
912 i = C_XFLAGS; /* crotchet index */
913 w = space_tb[i];
914 for ( ; --i >= 0; ) {
915 w /= cfmt.notespacingfactor;
916 space_tb[i] = w;
918 i = C_XFLAGS;
919 w = space_tb[i];
920 for ( ; ++i < NFLAGS_SZ; ) {
921 w *= cfmt.notespacingfactor;
922 space_tb[i] = w;
925 break;
926 case FORMAT_F: {
927 int b;
929 g_fspc(p, (struct FONTSPEC *) fd->v);
930 b = strstr(p, "box") != 0;
931 switch (fd->subtype) {
932 case 1:
933 cfmt.partsbox = b;
934 break;
935 case 2:
936 cfmt.measurebox = b;
937 break;
938 case 3:
939 cfmt.gchordbox = b;
940 break;
942 break;
944 case FORMAT_U:
945 *((float *) fd->v) = scan_u(p);
946 if (fd->subtype == 1) {
947 float rmargin;
949 rmargin = (cfmt.landscape ? cfmt.pageheight : cfmt.pagewidth)
950 - staffwidth - cfmt.leftmargin;
951 if (rmargin < 0)
952 fprintf(stderr, "'staffwidth' too big\n");
953 cfmt.rightmargin = rmargin;
955 break;
956 case FORMAT_B:
957 *((int *) fd->v) = g_logv(p);
958 break;
959 case FORMAT_S: {
960 int l;
962 l = strlen(p) + 1;
963 *((char **) fd->v) = getarena(l);
964 if (*p == '"')
965 get_str(*((char **) fd->v), p, l);
966 else strcpy(*((char **) fd->v), p);
967 break;
972 /* -- remove the spaces and comments of a format line -- */
973 static char *clean_line(char *p)
975 int i;
976 char c, *q;
978 while (isspace((unsigned char) *p))
979 p++;
980 q = p;
981 i = 0;
982 for (;;) {
983 if ((c = *p++) == '%') {
984 if (i > 0 && p[-2] != '\\')
985 c = '\0';
987 if (c == '\0') {
988 p--;
989 break;
991 i++;
993 while (--i > 0) {
994 c = *--p;
995 if (!isspace((unsigned char) c)) {
996 p[1] = '\0';
997 break;
1000 return q;
1003 /* -- lock a format -- */
1004 void lock_fmt(void *fmt)
1006 struct format *fd;
1008 for (fd = format_tb; fd->name; fd++)
1009 if (fd->v == fmt)
1010 break;
1011 if (fd->name == 0)
1012 return;
1013 fd->lock = 1;
1016 /* -- open a file for reading -- */
1017 FILE *open_file(char *fn, /* file name */
1018 char *ext, /* file type */
1019 char *rfn) /* real file name */
1021 FILE *fp;
1022 char *p;
1023 int l;
1025 strcpy(rfn, fn);
1026 if ((fp = fopen(rfn, "r")) != 0)
1027 return fp;
1028 strext(rfn, ext);
1029 if ((fp = fopen(rfn, "r")) != 0)
1030 return fp;
1031 if (in_fname != 0
1032 && (p = strrchr(in_fname, DIRSEP)) != 0) {
1033 l = p - in_fname + 1;
1034 strncpy(rfn, in_fname, l);
1035 strcpy(&rfn[l], fn);
1036 if ((fp = fopen(rfn, "r")) != 0)
1037 return fp;
1038 strext(&rfn[l], ext);
1039 if ((fp = fopen(rfn, "r")) != 0)
1040 return fp;
1042 if (*styd == '\0')
1043 return 0;
1044 sprintf(rfn, "%s%c%s", styd, DIRSEP, fn);
1045 if ((fp = fopen(rfn, "r")) != 0)
1046 return fp;
1047 strext(rfn, ext);
1048 if ((fp = fopen(rfn, "r")) != 0)
1049 return fp;
1050 return 0;
1053 /* -- read a format file -- */
1054 int read_fmt_file(char *fn)
1056 FILE *fp;
1057 char line[BSIZE], *p, *q;
1059 line[0] = '\001';
1060 if ((fp = open_file(fn, "fmt", &line[1])) == 0)
1061 return -1;
1062 if (strcmp(&line[strlen(line) - 3], ".ps") == 0) {
1063 if (!file_initialized)
1064 user_ps_add(line);
1065 else
1066 error(0, 0, "Cannot include the file %s", &line[1]);
1067 fclose(fp);
1068 return 0;
1070 for (;;) {
1071 p = line;
1072 if (!fgets(p, sizeof line, fp))
1073 break;
1074 p = clean_line(p);
1075 if (*p == '\0')
1076 continue;
1077 if (strcmp(p, "beginps") == 0) {
1078 for (;;) {
1079 p = line;
1080 if (!fgets(p, sizeof line, fp))
1081 break;
1082 #if 1
1084 int i;
1085 char c;
1087 i = strlen(p);
1088 while (--i > 0) {
1089 c = p[i];
1090 if (!isspace((unsigned char) c)) {
1091 p[i + 1] = '\0';
1092 break;
1096 #else
1097 p = clean_line(p);
1098 #endif
1099 if (*p == '\0')
1100 continue;
1101 if (strcmp(p, "endps") == 0)
1102 break;
1103 if (!file_initialized)
1104 user_ps_add(p);
1105 else
1106 PUT1("%s\n", p);
1108 continue;
1110 if (strcmp(p, "end") == 0)
1111 break;
1112 q = p;
1113 while (*p != '\0' && !isspace((unsigned char) *p))
1114 p++;
1115 if (*p != '\0') {
1116 *p++ = '\0';
1117 while (isspace((unsigned char) *p))
1118 p++;
1120 interpret_fmt_line(q, p, 0);
1122 fclose(fp);
1123 return 0;
1126 /* -- start a new font -- */
1127 void set_font(int ft)
1129 int fnum;
1130 struct FONTSPEC *f, *f2;
1132 if (ft == outft)
1133 return;
1134 f = &cfmt.font_tb[ft];
1135 f2 = &cfmt.font_tb[outft];
1136 outft = ft;
1137 if (f->fnum == f2->fnum && f->size == f2->size)
1138 return;
1139 fnum = f->fnum;
1140 if (!used_font[fnum]) {
1141 error(1, 0,
1142 "Font \"%s\" not predefined; using first in list",
1143 fontnames[fnum]);
1144 fnum = 0;
1146 if (f->size == 0)
1147 error(0, 0, "Font \"%s\" with a null size",
1148 fontnames[fnum]);
1149 PUT2("%.1f F%d ", f->size, fnum);