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.
34 char tex_buf
[TEX_BUF_SZ
]; /* result of tex_str() */
35 int outft
= -1; /* last font in the output file */
37 static char *strop
; /* current string output operation */
38 static float strlw
; /* line width */
39 static float strtw
= -1; /* current text width */
40 static int strns
; /* number of spaces (justify) */
41 static int curft
; /* current (wanted) font */
42 static int defft
; /* default font */
43 static int strtx
; /* PostScript text outputing */
45 /* width of characters according to the encoding */
46 /* these are the widths for Times-Roman, extracted from the 'a2ps' package */
47 static short ISOLatin1_w
[256] = {
48 0, 0, 0, 0, 0, 0, 0, 0, /* \002: hyphen in lyrics */
49 0, 0, 0, 0, 0, 0, 0, 0,
50 0, 0, 0, 0, 0, 0, 0, 0,
51 0, 0, 0, 0, 0, 0, 0, 0,
52 250,333,408,500,500,833,778,333,
53 333,333,500,564,250,564,250,278,
54 500,500,500,500,500,500,500,500,
55 500,500,278,278,564,564,564,444,
56 921,722,667,667,722,611,556,722,
57 722,333,389,722,611,889,722,722,
58 556,722,667,556,611,722,722,944,
59 722,722,611,333,278,333,469,500,
60 333,444,500,444,500,444,333,500,
61 500,278,278,500,278,778,500,500,
62 500,500,333,389,278,500,500,722,
63 500,500,444,480,200,480,541, 0,
64 0,500,500,500, 0, 0, 0, 0, /* \201..\203: sharp, flat and natural signs */
65 0, 0, 0, 0, 0, 0, 0, 0,
66 0, 0, 0, 0, 0, 0, 0, 0,
67 0, 0, 0, 0, 0, 0, 0, 0,
68 250,333,500,500,500,500,200,500,
69 333,760,276,500,564,333,760,333,
70 400,564,300,300,333,500,453,350,
71 333,278,310,500,750,750,750,444,
72 722,722,722,722,722,722,889,667,
73 611,611,611,611,333,333,333,333,
74 722,722,722,722,722,722,722,564,
75 722,722,722,722,722,722,556,500,
76 444,444,444,444,444,444,667,444,
77 444,444,444,444,278,278,278,278,
78 500,500,500,500,500,500,500,564,
79 500,500,500,500,500,500,500,500,
81 static short ISOLatin2_w
[96] = {
82 250,500,333,611,500,500,500,500,
83 333,556,500,500,500,333,611,500,
84 400,500,333,278,333,500,500,333,
85 333,389,500,500,500,333,444,500,
86 500,722,722,500,722,500,500,667,
87 500,611,500,611,500,333,333,500,
88 500,500,500,722,722,500,722,564,
89 500,500,722,500,722,722,500,500,
90 500,444,444,500,444,500,500,444,
91 500,444,500,444,500,278,278,500,
92 500,500,500,500,500,500,500,564,
93 500,500,500,500,500,500,500,333,
95 static short ISOLatin3_w
[96] = {
96 250,500,333,500,500,500,500,500,
97 333,500,500,500,500,333,760,500,
98 400,500,300,300,333,500,500,350,
99 333,278,500,500,500,750,750,500,
100 722,722,722,722,722,500,500,667,
101 611,611,611,611,333,333,333,333,
102 722,722,722,722,722,500,722,564,
103 500,722,722,722,722,500,500,500,
104 444,444,444,444,444,500,500,444,
105 444,444,444,444,278,278,278,278,
106 500,500,500,500,500,500,500,564,
107 500,500,500,500,500,500,500,333,
109 static short ISOLatin4_w
[96] = {
110 250,500,500,500,500,500,500,500,
111 333,556,500,500,500,333,611,333,
112 400,500,333,500,333,500,500,333,
113 333,389,500,500,500,500,444,500,
114 500,722,722,722,722,722,889,500,
115 500,611,500,611,500,333,333,500,
116 722,500,500,500,722,722,722,564,
117 722,500,722,722,722,500,500,500,
118 500,444,444,444,444,444,667,500,
119 500,444,500,444,500,278,278,500,
120 500,500,500,500,500,500,500,564,
121 500,500,500,500,500,500,500,333,
123 static short ISOLatin5_w
[96] = {
124 250,333,500,500,500,500,200,500,
125 333,760,276,500,564,333,760,333,
126 400,564,300,300,333,500,453,350,
127 333,278,310,500,750,750,750,444,
128 722,722,722,722,722,722,889,667,
129 611,611,611,611,333,333,333,333,
130 500,722,722,722,722,722,722,564,
131 722,722,722,722,722,500,500,500,
132 444,444,444,444,444,444,667,444,
133 444,444,444,444,278,278,278,278,
134 500,500,500,500,500,500,500,564,
135 500,500,500,500,500,278,500,500,
137 static short ISOLatin6_w
[96] = {
138 250,500,500,500,500,500,500,500,
139 333,500,556,500,611,333,500,500,
140 500,500,500,500,500,500,500,500,
141 500,500,389,500,444,500,500,500,
142 500,722,722,722,722,722,889,500,
143 500,611,500,611,500,333,333,333,
144 500,500,500,722,722,722,722,500,
145 722,500,722,722,722,722,556,500,
146 500,444,444,444,444,444,667,500,
147 500,444,500,444,500,278,278,278,
148 500,500,500,500,500,500,500,500,
149 500,500,500,500,500,500,500,500,
152 static short *cw_tb
[] = {
153 ISOLatin1_w
, /* 0 = ascii */
162 /* escaped character table */
163 /* adapted from the 'recode' package - first index is 128 + 32 */
164 static char ISOLatin1_c
[] =
165 "NS!!CtPdCuYeBBSE':Co-a<<NO--Rg'-DG+-2S3S''MyPI.M',1S-o>>141234?I"
166 "A!A'A>A?A:AAAEC,E!E'E>E:I!I'I>I:D-N?O!O'O>O?O:*XO/U!U'U>U:Y'THss"
167 "a!a'a>a?a:aaaec,e!e'e>e:i!i'i>i:d-n?o!o'o>o?o:-:o/u!u'u>u:y'thy:";
168 static char ISOLatin2_c
[] =
169 "NSA;'(L/CuL<S'SE':S<S,T<Z'--Z<Z.DGa;';l/''l<s''<',s<s,t<z''\"z<z."
170 "R'A'A>A(A:L'C'C,C<E'E;E:E<I'I>D<D/N'N<O'O>O\"O:*XR<U0U'U\"U:Y'T,ss"
171 "r'a'a>a(a:l'c'c,c<e'e;e:e<i'i>d<d/n'n<o'o>o\"o:-:r<u0u'u\"u:y't,'.";
172 static char ISOLatin3_c
[] =
173 "NSH/'(PdCu H>SE':I.S,G(J>-- Z.DGh/2S3S''Myh>.M',i.s,g(j>12 z."
174 "A!A'A> A:C.C>C,E!E'E>E:I!I'I>I: N?O!O'O>G.O:*XG>U!U'U>U:U(S>ss"
175 "a!a'a> a:c.c>c,e!e'e>e:i!i'i>i: n?o!o'o>g.o:-:g>u!u'u>u:u(s>'.";
176 static char ISOLatin4_c
[] =
177 "NSA;kkR,CuI?L,SE':S<E-G,T/--Z<'-DGa;';r,''i?l,'<',s<e-g,t/NGz<ng"
178 "A-A'A>A?A:AAAEI;C<E'E;E:E.I'I>I-D/N,O-K,O>O?O:*XO/U;U'U>U:U?U-ss"
179 "a-a'a>a?a:aaaei;c<e'e;e:e.i'i>i-d/n,o-k,o>o?o:-:o/u;u'u>u:u?u-'.";
180 static char ISOLatin5_c
[] =
181 "NS!!CtPdCuYeBBSE':Co-a<<NO--Rg'-DG+-2S3S''MyPI.M',1S-o>>141234?I"
182 "A!A'A>A?A:AAAEC,E!E'E>E:I!I'I>I:G(N?O!O'O>O?O:*XO/U!U'U>U:I.S,ss"
183 "a!a'a>a?a:aaaec,e!e'e;e:e.i'i>i-g(n?o!o'o>o?o:-:o/u!u'u>u:i.s,y:";
184 static char ISOLatin6_c
[] =
185 "NSA;E-G,I-I?K,L,N'R,S<T/Z<--kkNGd/a;e-g,i-i?k,l,n'r,s<t/z<SEssng"
186 "A-A'A>A?A:AAAEI;C<E'E;E:E.I'I>I:D/N,O-O'O>O?O:U?O/U;U'U>U:Y'THU-"
187 "a-a'a>a?a:aaaei;c<e'e;e:e.i'i>i:d-n,o-o'o>o?o:u?o/u;u'u>u:y'thu-";
188 static char *esc_tb
[] = {
189 ISOLatin1_c
, /* 0 = ascii */
203 static char *trim_title(char *p
, int first
);
205 /* -- print message for internal error and maybe stop -- */
206 void bug(char *msg
, int fatal
)
208 error(1, 0, "Internal error: %s.", msg
);
210 fprintf(stderr
, "Emergency stop.\n\n");
213 fprintf(stderr
, "Trying to continue...\n");
216 /* -- print an error message -- */
217 void error(int sev
, /* 0: warning, 1: error */
222 static struct SYMBOL
*t
;
224 if (t
!= info
['T' - 'A']) {
229 while (isspace((unsigned char) *p
))
231 fprintf(stderr
, " - In tune `%s':\n", p
);
233 fprintf(stderr
, sev
== 0 ? "Warning " : "Error ");
235 fprintf(stderr
, "in line %d.%d",
236 s
->as
.linenum
, s
->as
.colnum
);
238 s
->as
.flags
|= ABC_F_ERROR
;
242 fprintf(stderr
, ": ");
244 vfprintf(stderr
, fmt
, args
);
246 fprintf(stderr
, "\n");
249 /* -- read a number with a unit -- */
250 float scan_u(char *str
)
255 if (sscanf(str
, "%f%n", &a
, &nch
) == 1) {
256 if (str
[nch
] == '\0' || str
[nch
] == ' ')
258 if (!strncasecmp(str
+ nch
, "cm", 2))
260 if (!strncasecmp(str
+ nch
, "in", 2))
262 if (!strncasecmp(str
+ nch
, "pt", 2))
265 error(1, 0, "\n++++ Unknown unit value \"%s\"", str
);
269 /* -- capitalize a string -- */
270 static void cap_str(char *p
)
274 /* pb with toupper - works with ASCII only */
277 c
= (unsigned char) *p
;
278 if ((c
>= 'a' && c
<= 'z')
279 || (c
>= 0xe0 && c
<= 0xfe))
282 *p
= toupper((unsigned char) *p
);
288 /* -- return the character width -- */
289 float cwid(unsigned char c
)
294 if ((enc
= cfmt
.encoding
) >= sizeof cw_tb
/ sizeof cw_tb
[0])
296 if (c
< 160) /* (0xa0) */
299 return (float) w
[c
] / 1000.;
302 /* -- change string taking care of some tex-style codes -- */
303 /* Puts \ in front of ( and ) in case brackets are not balanced,
304 * interprets all ISOLatin1..6 escape sequences as defined in rfc1345.
305 * Returns an estimated width of the string. */
306 float tex_str(char *s
)
308 char *d
, c1
, c2
, *p_enc
, *p
;
314 maxlen
= sizeof tex_buf
- 1; /* have room for EOS */
315 if ((i
= curft
) <= 0)
317 swfac
= cfmt
.font_tb
[i
].swfac
;
318 i
= font_enc
[cfmt
.font_tb
[i
].fnum
];
319 if ((unsigned) i
>= sizeof esc_tb
/ sizeof esc_tb
[0])
322 while ((c1
= *s
++) != '\0') {
324 case '\\': /* backslash sequences */
334 if (c1
== '\\' || (c2
= *s
) == '\0') {
340 /* treat escape with octal value */
341 if ((unsigned) (c1
- '0') <= 3
342 && (unsigned) (c2
- '0') <= 7
343 && (unsigned) (s
[1] - '0') <= 7) {
344 c1
= ((c1
- '0') << 6) + ((c2
- '0') << 3) + s
[1] - '0';
348 /* convert to rfc1345 */
350 case '`': c1
= '!'; break;
351 case '^': c1
= '>'; break;
352 case '~': c1
= '?'; break;
353 case '"': c1
= ':'; break;
354 /* special TeX sequences */
355 case 'O': c1
= '/'; c2
= 'O'; s
--; break;
356 case 'o': c1
= '/'; c2
= 'o'; s
--; break;
357 case 'c': if (c2
== 'c' || c2
== 'C')
362 case '`': c2
= '!'; break;
363 case '^': c2
= '>'; break;
364 case '~': c2
= '?'; break;
365 case '"': c2
= ':'; break;
367 for (i
= 32 * 3, p
= p_enc
; --i
>= 0; p
+= 2) {
368 if ((*p
== c1
&& p
[1] == c2
)
369 || (*p
== c2
&& p
[1] == c1
)) {
371 c1
= (p
- p_enc
) / 2 + 128 + 32;
379 if (isdigit((unsigned char) *s
)
380 && (unsigned) (*s
- '0') < FONT_UMAX
) {
384 swfac
= cfmt
.font_tb
[i
].swfac
;
385 i
= cfmt
.font_tb
[i
].fnum
;
387 if ((unsigned) i
>= sizeof esc_tb
/ sizeof esc_tb
[0])
394 goto addchar_nowidth
;
404 case ')': /* ( ) becomes \( \) */
410 w
+= cwid((unsigned char) c1
) * swfac
;
420 /* -- set the default font of a string -- */
421 void str_font(int ft
)
426 /* -- get the current default font -- */
427 int get_str_font(void)
432 /* -- output one string -- */
433 static void str_ft_out1(char *p
, int l
)
435 if (curft
!= outft
) {
451 /* -- output a string and the font changes -- */
452 static void str_ft_out(char *p
, int end
)
459 if (isdigit((unsigned char) p
[1])
460 && (unsigned) (p
[1] - '0') < FONT_UMAX
) {
462 str_ft_out1(q
, p
- q
);
463 if (curft
!= p
[1] - '0') {
473 str_ft_out1(q
, p
- q
);
480 str_ft_out1(q
, p
- q
);
487 /* -- output a string, handling the font changes -- */
488 void str_out(char *p
, int action
)
490 if (curft
<= 0) /* first call */
493 /* special case when font change at start of text */
494 /*---fixme: authorize 2 chars?*/
495 if (*p
== '$' && isdigit((unsigned char) p
[1])
496 && (unsigned) (p
[1] - '0') < FONT_UMAX
) {
497 if (curft
!= p
[1] - '0') {
505 /* direct output if no font change */
506 if (strchr(p
, '$') == 0) {
510 if (action
== A_CENTER
)
512 else if (action
== A_RIGHT
)
515 PUT2("(%s)show%s ", p
, op
);
519 /* if not left aligned, build a PS function */
520 if (action
== A_LEFT
)
528 str_ft_out(p
, 1); /* output the string */
530 /* if not left aligned, call the PS function */
531 if (action
== A_LEFT
)
534 "/strop/strw load def/w 0 def str w ");
535 if (action
== A_CENTER
)
537 PUT0("neg 0 RM/strop/show load def str ");
540 /* -- output a string with TeX translation -- */
541 void put_str(char *str
, int action
)
544 str_out(tex_buf
, action
);
548 /* -- output a header information -- */
549 static void put_inf(struct SYMBOL
*s
)
556 while (isspace((unsigned char) *p
))
561 /* -- output a header format '111 (222)' -- */
562 static void put_inf2r(struct SYMBOL
*s1
,
566 char buf
[256], *p
, *q
;
575 while (isspace((unsigned char) *p
))
577 if (s1
->as
.text
[0] == 'T' && s1
->as
.text
[1] == ':')
578 p
= trim_title(p
, s1
== info
['T' - 'A']);
580 buf
[sizeof buf
- 1] = '\0';
581 strncpy(buf
, p
, sizeof buf
- 1);
582 q
= buf
+ strlen(buf
);
583 if (q
< buf
+ sizeof buf
- 4) {
589 while (isspace((unsigned char) *p
))
591 strncpy(q
, p
, buf
+ sizeof buf
- 2 - q
);
601 /* -- add text to a block -- */
602 void add_to_text_block(char *s
, int job
)
608 /* if first line, set the fonts */
611 strlw
= ((cfmt
.landscape
? cfmt
.pageheight
: cfmt
.pagewidth
)
612 - cfmt
.leftmargin
- cfmt
.rightmargin
) / cfmt
.scale
;
616 f
= &cfmt
.font_tb
[curft
];
617 else f
= &cfmt
.font_tb
[defft
];
618 baseskip
= f
->size
* cfmt
.lineskipfac
;
621 if (job
== T_LEFT
|| job
== T_CENTER
|| job
== T_RIGHT
) {
627 } else if (job
== T_CENTER
) {
628 PUT1("%.1f 0 M ", strlw
* 0.5);
629 put_str(s
, A_CENTER
);
631 PUT1("%.1f 0 M ", strlw
);
635 bskip(baseskip
* 0.5);
642 /* fill or justify lines */
643 if (strtw
< 0) { /* if first line */
658 if (*s
== '\0') { /* empty line */
663 if (job
== T_JUSTIFY
)
665 "/strop/show load def str\n");
667 bskip(f
->size
* cfmt
.lineskipfac
* 1.5);
670 if (job
== T_JUSTIFY
) {
681 while (*p
!= ' ' && *p
!= '\0')
686 if (strtw
+ lw
> strlw
) {
691 if (job
== T_JUSTIFY
) {
695 "/strop/strw load def/w 0 def str"
696 "/w %.1f w sub %d div def"
697 "/strop/jshow load def str ",
701 bskip(cfmt
.font_tb
[curft
].size
* cfmt
.lineskipfac
);
703 if (job
== T_JUSTIFY
) {
711 strtw
+= cwid(' ') * cfmt
.font_tb
[curft
].swfac
;
714 str_ft_out(tex_buf
, 0);
725 /* -- write a text block -- */
726 void write_text_block(int job
, int abc_state
)
735 if (job
== T_JUSTIFY
)
737 "/strop/show load def str\n");
738 else if (job
== T_FILL
)
740 bskip(cfmt
.font_tb
[TEXTFONT
].size
* cfmt
.parskipfac
);
743 /* next line to allow pagebreak after each paragraph */
744 if (!epsf
&& abc_state
!= ABC_S_TUNE
)
749 /* -- output a line of words after tune -- */
750 static int put_wline(char *p
,
756 while (isspace((unsigned char) *p
))
758 if (*p
== '$' && isdigit((unsigned char) p
[1])
759 && (unsigned) (p
[1] - '0') < FONT_UMAX
) {
760 if (curft
!= p
[1] - '0') {
769 if (isdigit((unsigned char) *p
) || p
[1] == '.') {
782 /* on the left side, permit page break at empty lines or stanza start */
784 && (*p
== '\0' || r
!= 0))
790 PUT1("%.1f 0 M ", x
);
795 PUT1("%.1f 0 M ", x
+ 5);
798 return *p
== '\0' && r
== 0;
801 /* -- output the words after tune -- */
802 void put_words(struct SYMBOL
*words
)
804 struct SYMBOL
*s
, *s_end
, *s2
;
806 int i
, n
, have_text
, max2col
;
811 /* see if we may have 2 columns */
812 middle
= 0.5 * ((cfmt
.landscape
? cfmt
.pageheight
: cfmt
.pagewidth
)
813 - cfmt
.leftmargin
- cfmt
.rightmargin
) / cfmt
.scale
;
814 max2col
= (int) ((middle
- 45.) / (cwid('a') * cfmt
.font_tb
[WORDSFONT
].swfac
));
817 for (s
= words
; s
!= 0; s
= s
->next
) {
819 while (isspace((unsigned char) *p
))
821 if (strlen(p
) > max2col
) {
830 } else have_text
= 1;
839 p
= &s_end
->as
.text
[2];
840 while (isspace((unsigned char) *p
))
843 if (have_text
&& --i
<= 0)
846 } else have_text
= 1;
855 /* output the text */
856 bskip(cfmt
.wordsspace
);
857 for (s
= words
; s
!= 0 || s2
!= 0; ) {
858 bskip(cfmt
.lineskipfac
* cfmt
.font_tb
[WORDSFONT
].size
);
860 put_wline(&s
->as
.text
[2], 45., 0);
866 if (put_wline(&s2
->as
.text
[2], 20. + middle
, 1)) {
870 else if (s2
->next
!= 0) {
872 /* center the last words */
873 /*fixme: should compute the width average.. */
884 /* -- output history -- */
885 void put_history(void)
887 struct SYMBOL
*s
, *s2
;
890 bskip(cfmt
.textspace
);
891 str_font(HISTORYFONT
);
892 for (s
= info
['I' - 'A']; s
!= 0; s
= s
->next
) {
893 if ((s2
= info
[s
->as
.text
[0] - 'A']) == 0)
895 get_str(tex_buf
, &s
->as
.text
[1], 256);
896 h
= cfmt
.font_tb
[HISTORYFONT
].size
* cfmt
.lineskipfac
;
897 set_font(HISTORYFONT
);
898 PUT1("0 0 M(%s)show ", tex_buf
);
901 if ((s2
= s2
->next
) == 0)
911 /* -- move trailing "The" to front, set to uppercase letters or add xref -- */
912 static char *trim_title(char *p
, int first
)
916 static char buf
[256];
919 if (cfmt
.titletrim
) {
922 if (q
[1] != ' ' || !isupper(q
[2])
923 || strchr(q
+ 2, ' ') != 0)
927 if (q
== 0 && !cfmt
.titlecaps
&& !(first
&& cfmt
.withxrefs
))
928 return p
; /* keep the title as it is */
930 if (first
&& cfmt
.withxrefs
)
931 b
+= sprintf(b
, "%s. ", &info
['X' - 'A']->as
.text
[2]);
937 if (l
> buf
+ sizeof buf
- b
- 1)
938 l
= buf
+ sizeof buf
- b
- 1;
939 } else l
= buf
+ sizeof buf
- b
- 1;
947 /* -- write a title -- */
948 void write_title(struct SYMBOL
*s
)
953 while (isspace((unsigned char) *p
))
957 p
= trim_title(p
, s
== info
['T' - 'A']);
958 if (s
== info
['T' - 'A']) {
959 bskip(cfmt
.titlespace
+ cfmt
.font_tb
[TITLEFONT
].size
);
962 bskip(cfmt
.subtitlespace
+ cfmt
.font_tb
[SUBTITLEFONT
].size
);
963 set_font(SUBTITLEFONT
);
967 else PUT1("%.1f 0 M(",
968 0.5 * ((cfmt
.landscape
? cfmt
.pageheight
: cfmt
.pagewidth
)
969 - cfmt
.leftmargin
- cfmt
.rightmargin
) / cfmt
.scale
);
971 PUT2("%s)show%s\n", tex_buf
, cfmt
.titleleft
? "" : "c");
974 /* -- write heading with format -- */
975 static void write_headform(float lwidth
)
981 float x
, y
, xa
[3], ya
[3], sz
, yb
[3];
988 memset(inf_nb
, 0, sizeof inf_nb
);
989 memset(inf_ft
, HISTORYFONT
, sizeof inf_ft
);
990 inf_ft
['A' - 'A'] = INFOFONT
;
991 inf_ft
['C' - 'A'] = COMPOSERFONT
;
992 inf_ft
['O' - 'A'] = COMPOSERFONT
;
993 inf_ft
['P' - 'A'] = PARTSFONT
;
994 inf_ft
['Q' - 'A'] = TEMPOFONT
;
995 inf_ft
['R' - 'A'] = INFOFONT
;
996 inf_ft
['T' - 'A'] = TITLEFONT
;
997 inf_ft
['X' - 'A'] = TITLEFONT
;
998 memcpy(inf_s
, info
, sizeof inf_s
);
999 memset(inf_sz
, 0, sizeof inf_sz
);
1000 inf_sz
['A' - 'A'] = cfmt
.infospace
;
1001 inf_sz
['C' - 'A'] = cfmt
.composerspace
;
1002 inf_sz
['O' - 'A'] = cfmt
.composerspace
;
1003 inf_sz
['R' - 'A'] = cfmt
.infospace
;
1004 p
= cfmt
.titleformat
;
1007 while (isspace((unsigned char) *p
))
1012 if ((unsigned) i
< 26) {
1027 if (j
< sizeof fmt
- 4) {
1031 } else if (*p
== ',') {
1032 if (j
< sizeof fmt
- 3)
1033 fmt
[j
++] = 126; /* next line */
1034 } else if (*p
== '+') {
1035 if (j
> 0 && fmt
[j
- 1] < 125
1036 && j
< sizeof fmt
- 3)
1037 fmt
[j
++] = 125; /* concatenate */
1038 /*new fixme: add free text "..." ?*/
1042 fmt
[j
++] = 126; /* newline */
1043 fmt
[j
] = 127; /* end of format */
1045 ya
[0] = ya
[1] = ya
[2] = cfmt
.titlespace
;;
1047 xa
[1] = lwidth
* 0.5;
1052 yb
[0] = yb
[1] = yb
[2] = y
= 0;
1056 if (i
>= 126) /* if newline */
1059 if (yb
[align
+ 1] != 0)
1062 if (s
== 0 || inf_nb
[i
] == 0)
1065 f
= &cfmt
.font_tb
[j
];
1066 sz
= f
->size
* 1.1 + inf_sz
[i
];
1070 /*fixme:should count the height of the concatenated field*/
1074 for (i
= 0; i
< 3; i
++)
1078 if (i
>= 126) /* if newline */
1082 if (s
== 0 || inf_nb
[i
] == 0)
1087 f
= &cfmt
.font_tb
[j
];
1088 sz
= f
->size
* 1.1 + inf_sz
[i
];
1089 y
= ya
[align
+ 1] + sz
;
1090 PUT2("%.1f %.1f M ", x
, -y
);
1091 if (*p
== 125) { /* concatenate */
1093 /*fixme: do it work with different fields*/
1094 if (*p
== i
&& p
[1] == align
1101 while (isspace((unsigned char) *q
))
1104 q
= trim_title(q
, s
== inf_s
['T' - 'A']);
1105 strncpy(buf
, q
, sizeof buf
- 1);
1106 buf
[sizeof buf
- 1] = '\0';
1108 if (j
< sizeof buf
- 1) {
1116 while (isspace((unsigned char) *q
))
1118 if (s
->as
.text
[0] == 'T' && s
->as
.text
[1] == ':')
1119 q
= trim_title(q
, 0);
1120 r
= buf
+ strlen(buf
);
1121 strncpy(r
, q
, buf
+ sizeof buf
- r
- 1);
1123 str_out(tex_buf
, align
);
1128 } else if (i
== 'Q' - 'A') { /* special case for tempo */
1129 if (align
!= A_LEFT
) {
1133 if (align
== A_CENTER
)
1134 PUT1("-%.1f 0 RM ", w
* 0.5);
1135 else PUT1("-%.1f 0 RM ", w
);
1137 write_tempo(s
, 0, 0.75);
1138 } else put_inf2r(s
, 0, align
);
1139 if (inf_s
[i
] == info
['T' - 'A']) {
1140 inf_ft
[i
] = SUBTITLEFONT
;
1141 str_font(SUBTITLEFONT
);
1142 f
= &cfmt
.font_tb
[SUBTITLEFONT
];
1143 inf_sz
[i
] = cfmt
.subtitlespace
;
1144 sz
= f
->size
* 1.1 + inf_sz
[i
];
1147 if (inf_nb
[i
] == 1) {
1150 PUT2("%.1f %.1f M ", x
, -y
);
1151 put_inf2r(s
, 0, align
);
1167 ya
[1] = ya
[2] = ya
[0];
1171 /* -- output the tune heading -- */
1172 void write_heading(struct abctune
*t
)
1174 struct SYMBOL
*s
, *rhythm
, *area
, *author
;
1175 float lwidth
, down1
, down2
;
1177 lwidth
= ((cfmt
.landscape
? cfmt
.pageheight
: cfmt
.pagewidth
)
1178 - cfmt
.leftmargin
- cfmt
.rightmargin
) / cfmt
.scale
;
1180 if (cfmt
.titleformat
!= 0) {
1181 write_headform(lwidth
);
1182 bskip(cfmt
.musicspace
);
1187 for (s
= info
['T' - 'A']; s
!= 0; s
= s
->next
)
1190 /* rhythm, composer, origin */
1191 down1
= cfmt
.composerspace
+ cfmt
.font_tb
[COMPOSERFONT
].size
;
1192 rhythm
= (first_voice
->key
.bagpipe
&& !cfmt
.infoline
) ? info
['R' - 'A'] : 0;
1194 str_font(COMPOSERFONT
);
1196 -(cfmt
.composerspace
+ cfmt
.font_tb
[COMPOSERFONT
].size
));
1198 down1
-= cfmt
.font_tb
[COMPOSERFONT
].size
;
1201 if (t
->abc_vers
< 2)
1202 area
= info
['A' - 'A'];
1203 else author
= info
['A' - 'A'];
1204 if ((s
= info
['C' - 'A']) != 0 || info
['O' - 'A'] || author
!= 0) {
1208 str_font(COMPOSERFONT
);
1209 bskip(cfmt
.composerspace
);
1210 if (cfmt
.aligncomposer
< 0) {
1213 } else if (cfmt
.aligncomposer
== 0) {
1214 xcomp
= lwidth
* 0.5;
1223 bskip(cfmt
.font_tb
[COMPOSERFONT
].size
);
1224 down2
+= cfmt
.font_tb
[COMPOSERFONT
].size
;
1227 if ((author
= author
->next
) == 0)
1231 if ((s
= info
['C' - 'A']) != 0 || info
['O' - 'A']) {
1232 if (cfmt
.aligncomposer
>= 0
1234 bskip(down1
- down2
);
1236 bskip(cfmt
.font_tb
[COMPOSERFONT
].size
);
1237 PUT1("%.1f 0 M ", xcomp
);
1239 (s
== 0 || s
->next
== 0) ? info
['O' - 'A'] : 0,
1243 if ((s
= s
->next
) == 0)
1245 down1
+= cfmt
.font_tb
[COMPOSERFONT
].size
;
1248 bskip(down2
- down1
);
1251 rhythm
= rhythm
? 0 : info
['R' - 'A'];
1252 if ((rhythm
|| area
) && cfmt
.infoline
) {
1254 /* if only one of rhythm or area then do not use ()'s
1255 * otherwise output 'rhythm (area)' */
1257 bskip(cfmt
.font_tb
[INFOFONT
].size
+ cfmt
.infospace
);
1258 PUT1("%.1f 0 M ", lwidth
);
1259 put_inf2r(rhythm
, area
, A_RIGHT
);
1260 down1
+= cfmt
.font_tb
[INFOFONT
].size
+ cfmt
.infospace
;
1263 } else down2
= cfmt
.composerspace
+ cfmt
.font_tb
[COMPOSERFONT
].size
;
1266 if (info
['P' - 'A']) {
1267 down1
= cfmt
.partsspace
+ cfmt
.font_tb
[PARTSFONT
].size
- down1
;
1272 str_font(PARTSFONT
);
1274 put_inf(info
['P' - 'A']);
1277 bskip(down2
+ cfmt
.musicspace
);
1280 /* -- memorize a PS line -- */
1281 void user_ps_add(char *s
)
1287 t
= (struct u_ps
*) malloc(sizeof *user_ps
- sizeof user_ps
->text
1291 if ((r
= user_ps
) == 0)
1294 while (r
->next
!= 0)
1300 /* -- output the user defined postscript sequences -- */
1301 void user_ps_write(void)
1305 if ((t
= user_ps
) == 0)
1309 if (t
->text
[0] == '\001') { /* PS file */
1313 if ((f
= fopen(&t
->text
[1], "r")) == 0) {
1314 error(1, 0, "Cannot open PS file '%s'",
1317 while (fgets(line
, sizeof line
, f
)) /* copy the file */
1318 fwrite(line
, 1, strlen(line
), fout
);
1321 } else fprintf(fout
, "%s\n", t
->text
);