subs.h - abc2ps - A powerful sheet setting tool using the simple abc notation
(HTM) git clone git://vernunftzentrum.de/abc2ps.git
(DIR) Log
(DIR) Files
(DIR) Refs
---
subs.h (37054B)
---
1 /*
2 * This file is part of abc2ps,
3 * Copyright (C) 1996,1997,1998 Michael Methfessel
4 * See file abc2ps.c for details.
5 */
6
7 /* miscellaneous subroutines */
8
9 /* ----- write_help ----- */
10 void write_help ()
11 {
12
13 printf ("abc2ps v%s.%s (%s, %s) compiled %s\n",
14 VERSION, REVISION, VDATE, STYLE, __DATE__);
15
16 printf ("Usage: abc2ps files.. [-e nums-or-pats] [other flags]\n"
17 " - show index of abc files or typeset tunes in Postscript.\n"
18 "where: files input files in abc format\n"
19 " nums tune xref numbers, i.e. 1 3 6-7,20-\n"
20 " pats patterns for title search\n"
21 "Tunes are selected if they match a number or a pattern.\n"
22 "Flags: -o write output for selected tunes\n"
23 " -E produce EPSF output, one tune per file\n"
24 " -O aa set outfile name to aaa\n"
25 " -O = make outfile name from infile/title\n"
26 " -i run in interactive mode\n"
27 " -v nn set verbosity level to nn\n"
28 " -h show this command summary\n"
29 " Selection:\n"
30 " -e following arguments are selectors\n"
31 " -f following arguments are file names\n"
32 " -T search Title field (default)\n"
33 " -C search Composer field instead of title\n"
34 " -R search Rhythm field instead of title\n"
35 " -S search Source field instead of title\n"
36 " -V str select voices, eg. -V 1,4-5\n"
37 " Formatting:\n"
38 " -H show the format parameters\n"
39 " -p pretty output (looks better, needs more space)\n"
40 " -P select second predefined pretty output style\n"
41 " -s xx set scale factor for symbol size to xx\n"
42 " -w xx set staff width (cm/in/pt)\n"
43 " -m xx set left margin (cm/in/pt)\n"
44 " -d xx set staff separation (cm/in/pt)\n"
45 " -x include xref numbers in output\n"
46 " -k nn number every nn bars; 0 for first in staff\n"
47 " -n include notes and history in output\n"
48 " -N write page numbers\n"
49 " -I write index to Ind.ps\n"
50 " -1 write one tune per page\n"
51 " -l landscape mode\n"
52 " -g xx set glue mode to shrink|space|stretch|fill\n"
53 " -F foo read format from \"foo.fmt\"\n"
54 " -D bar look for format files in directory \"bar\"\n"
55 " -X x set strictness for note spacing, 0<x<1 \n"
56 " Transposing:\n"
57 " -t n transpose by n halftones (_n for negative number)\n"
58 " -t XX transpose root up/down to note XX (eg. C A# ^Bb _Bb)\n"
59 " Line breaks:\n"
60 " -a xx set max shrinkage to xx (between 0 and 1)\n"
61 " -b break at all line ends (ignore continuations)\n"
62 " -c continue all line ends (append '\\')\n"
63 " -B bb put line break every bb bars\n"
64 " Alloc options:\n"
65 " -maxs n set maximal number of symbols (default %d)\n"
66 " -maxv n set maximal number of voices (default %d)\n"
67 , maxSyms, maxVc);
68 }
69
70
71 /* ----- write_version ----- */
72 void write_version ()
73 {
74
75 /* printf ("abc2ps v%s (%s, %s) compiled %s\n",
76 VERSION, VDATE, STYLE, __DATE__); */
77
78 printf ("abc2ps v%s.%s (%s, %s) compiled %s\n",
79 VERSION, REVISION, VDATE, STYLE, __DATE__);
80
81 if (strlen(DEFAULT_FDIR)>0)
82 printf ("Default format directory %s\n", DEFAULT_FDIR);
83
84 }
85
86 /* ----- is_xrefstr: check if string ok for xref selection ---- */
87 int is_xrefstr (str)
88 char str[];
89 {
90
91 char *c;
92 c=str;
93 while (*c != '\0') {
94 if ((!isdig(*c)) && (*c!='-') && (*c!=',') && (*c!=' ')) return 0;
95 c++;
96 }
97 return 1;
98 }
99
100
101 /* ----- make_arglist: splits one string into list or arguments ---- */
102 int make_arglist (str, av)
103 char str[];
104 char *av[];
105 {
106 char *q;
107 int n;
108
109 q=str;
110 n=1; /* first real arg is 1, as in argv */
111 for (;;) {
112 while (*q==' ') q++;
113 if (*q=='\0') break;
114 av[n]=q;
115 n++;
116 while ((*q!=' ') && (*q!='\0')) q++;
117 if (*q=='\0') break;
118 *q='\0';
119 q++;
120 }
121 return n;
122 }
123
124
125 /* ----- init_ops ----- */
126 void init_ops (job)
127 int job;
128 {
129
130 one_per_page = -1;
131 landscape = -1;
132 scalefac = -1.0;
133 lmargin = -1.0;
134 swidth = -1.0;
135 write_history = -1;
136 staffsep = -1;
137 dstaffsep = 0;
138 break_continues = -1;
139 continue_lines = -1;
140 include_xrefs = -1;
141 alfa_c = -1.0;
142 strict1 = -1.0;
143 strict2 = -1.0;
144 barnums = -1;
145 make_index = 0;
146
147 select_all = 0;
148 do_mode = DO_INDEX;
149 pagenumbers = 0;
150 strcpy (styf, "");
151 strcpy (transpose, "");
152 strcpy (vcselstr, "");
153
154 if (job) {
155 strcpy (styd, DEFAULT_FDIR);
156 strcpy (outf, OUTPUTFILE);
157 interactive = 0;
158 pretty = 0;
159 epsf = 0;
160 choose_outname = 0;
161 gmode = G_FILL;
162 vb = VERBOSE0;
163 search_field0 = S_TITLE;
164 }
165 }
166
167
168 /* ----- ops_into_fmt ----- */
169 void ops_into_fmt (fmt)
170 struct FORMAT *fmt;
171 {
172 if (landscape >= 0) fmt->landscape=landscape;
173 if (scalefac >= 0) fmt->scale=scalefac;
174 if (lmargin >= 0) fmt->leftmargin=lmargin;
175 if (swidth >= 0) fmt->staffwidth=swidth;
176 if (continue_lines >= 0) fmt->continueall=continue_lines;
177 if (break_continues >= 0) fmt->breakall=break_continues;
178 if (write_history >= 0) fmt->writehistory=write_history;
179 if (bars_per_line > 0) fmt->barsperstaff=bars_per_line;
180 if (include_xrefs >= 0) fmt->withxrefs=include_xrefs;
181 if (one_per_page >= 0) fmt->oneperpage=one_per_page;
182 if (alfa_c >= 0) fmt->maxshrink=alfa_c;
183 if (staffsep >= 0) fmt->staffsep=staffsep;
184 if (strict1 >= 0) fmt->strict1=strict1;
185 if (strict2 >= 0) fmt->strict2=strict2;
186 if (barnums >= 0) fmt->barnums=barnums;
187 fmt->staffsep = fmt->staffsep + dstaffsep;
188 fmt->sysstaffsep = fmt->sysstaffsep + dstaffsep;
189
190 }
191
192
193 /* ----- parse_args: parse list of arguments, interpret flags ----- */
194 int parse_args (ac, av)
195 int ac;
196 char *av[];
197 {
198 int i,m,k,nsel,sel_arg,j,ok,f_pos,got_value;
199 char c,aaa[201],ext[41];
200
201 help_me=0;
202 ninf=0;
203 nsel=0;
204 sel_arg=0;
205 f_pos=-1;
206 strcpy (sel_str[0], "");
207 s_field[0]=search_field0;
208
209 i=1;
210 while (i<ac) {
211
212 if (av[i][0]=='+') { /* switch off flags with '+' */
213 m=1;
214 k=strlen(av[i]);
215 while (m<k) {
216 c=av[i][m];
217 if (c=='b') break_continues=0;
218 else if (c=='c') continue_lines=0;
219 else if (c=='x') include_xrefs=0;
220 else if (c=='1') one_per_page=0;
221 else if (c=='B') bars_per_line=0;
222 else if (c=='i') interactive=0;
223 else if (c=='n') write_history=0;
224 else if (c=='l') landscape=0;
225 else if (c=='p') pretty=0;
226 else if (c=='E') epsf=0;
227 else if (c=='F') strcpy (styf, "");
228 else if (c=='N') pagenumbers=0;
229 else if (c=='O') { choose_outname=0; strcpy (outf, OUTPUTFILE); }
230 else {
231 printf ("+++ Cannot switch off flag: +%c\n", c);
232 return 1;
233 }
234 m++;
235 }
236 }
237
238 else if (av[i][0]=='-') { /* interpret a flag with '-'*/
239
240 /* identify fullword options first */
241 if (!strcmp(av[i],"-maxv")) {
242 if ((i==ac-1)||(av[i+1][0]=='-')) rx("missing parameter for ",av[i]);
243 sscanf(av[++i],"%d",&maxVc);
244 }
245 else if (!strcmp(av[i],"-maxs")) {
246 if ((i==ac-1)||(av[i+1][0]=='-')) rx("missing parameter for ",av[i]);
247 sscanf(av[++i],"%d",&maxSyms);
248 }
249
250 else {
251 m=1;
252 k=strlen(av[i]);
253 while (m<k) {
254 c=av[i][m];
255 if (c=='h') help_me=1; /* simple flags */
256 else if (c=='H') help_me=2;
257 else if (c=='e') sel_arg=1;
258 else if (c=='f') {
259 nsel++;
260 strcpy (sel_str[nsel], "");
261 if (ninf==0) { /* selector before first file */
262 strcpy(sel_str[nsel],sel_str[nsel-1]);
263 s_field[nsel]=s_field[nsel-1];
264 }
265 s_field[nsel]=search_field0;
266 sel_arg=0;
267 f_pos=i;
268 }
269 else if (c=='b') {break_continues=1; continue_lines=0;}
270 else if (c=='c') {continue_lines=1; break_continues=0;}
271 else if (c=='x') include_xrefs=1;
272 else if (c=='1') one_per_page=1;
273 else if (c=='i') interactive=1;
274 else if (c=='n') write_history=1;
275 else if (c=='l') landscape=1;
276 else if (c=='p') pretty=1;
277 else if (c=='P') pretty=2;
278 else if (c=='E') epsf=1;
279 else if (c=='o') do_mode=DO_OUTPUT;
280 else if (c=='N') pagenumbers=1;
281 else if (c=='I') make_index=1;
282 else if (strchr("TCRS",c)) {
283 if (c=='T') s_field[nsel]=S_TITLE;
284 if (c=='C') s_field[nsel]=S_COMPOSER;
285 if (c=='R') s_field[nsel]=S_RHYTHM;
286 if (c=='S') s_field[nsel]=S_SOURCE;
287 sel_arg=1;
288 }
289
290 else if (strchr("vsdwmgtkDFYBVXaO",c)) { /* flags with parameter.. */
291 strcpy (aaa, &av[i][m+1]);
292 if ((strlen(aaa)>0) && strchr("glO",c)) { /* no sticky arg */
293 printf ("+++ Incorrect usage of flag -%c\n", c);
294 return 1;
295 }
296
297 got_value=1; /* check for value */
298 if (strlen(aaa)==0) {
299 got_value=0;
300 i++;
301 if ((i>=ac) || (av[i][0]=='-'))
302 i--;
303 else {
304 strcpy (aaa,av[i]);
305 got_value=1;
306 }
307 }
308
309 if (got_value && strchr("vskYB",c)) { /* check num args */
310 ok=1;
311 for (j=0;j<strlen(aaa);j++)
312 if (!strchr("0123456789.",aaa[j])) ok=0;
313 if (!ok) {
314 printf ("+++ Invalid parameter <%s> for flag -%c\n",aaa,c);
315 return 1;
316 }
317 }
318
319 /* --- next ops require a value --- */
320
321 if (!got_value) { /* check value was given */
322 printf ("+++ Missing parameter after flag -%c\n", c);
323 return 1;
324 }
325
326 if (c=='k') {
327 sscanf(aaa,"%d",&barnums);
328 break;
329 }
330
331 if (c=='V') { /* -V flag */
332 ok=1;
333 strcpy (vcselstr, aaa);
334 }
335
336 if (c=='X') { /* -X flag */
337 ok=1;
338 if (aaa[0]==',') {
339 sscanf(aaa,",%f",&strict2);
340 if (strict2<-0.001 || strict2>1.001) ok=0;
341 }
342 else if (strchr(aaa,',')) {
343 sscanf (aaa,"%f,%f",&strict1,&strict2);
344 if (strict1<-0.001 || strict1>1.001) ok=0;
345 if (strict2<-0.001 || strict2>1.001) ok=0;
346 }
347 else {
348 sscanf(aaa,"%f",&strict1);
349 if (strict1<-0.001 || strict1>1.001) ok=0;
350 strict2=strict1;
351 }
352 if (!ok) {
353 printf ("+++ Invalid parameter <%s> for flag -%c\n",aaa,c);
354 return 1;
355 }
356 }
357
358 if (c=='O') { /* -O flag */
359 if (!strcmp(aaa,"=")) {
360 choose_outname=1;
361 }
362 else {
363 getext (aaa,ext);
364 if (strcmp(ext,"ps") && strcmp(ext,"eps") && strcmp(ext,"")) {
365 printf ("Wrong extension for output file: %s\n", aaa);
366 return 1;
367 }
368 strext (outf, aaa, "ps", 1);
369 choose_outname=0;
370 }
371 }
372
373 if (c=='a') {
374 sscanf (aaa, "%f", &alfa_c);
375 if ((alfa_c>1.05)||(alfa_c<-0.01)) {
376 printf ("+++ Bad parameter for flag -a: %s\n",aaa);
377 return 1;
378 }
379 }
380
381 if (c=='B') {
382 sscanf(aaa,"%d",&bars_per_line);
383 continue_lines=0;
384 }
385 if (c=='t') strcpy(transpose,aaa);
386 if (c=='v') sscanf(aaa,"%d",&vb);
387 if (c=='s') sscanf(aaa,"%f",&scalefac);
388 if (c=='d') {
389 if (aaa[0]=='+' || aaa[0]=='-') dstaffsep = scan_u(aaa);
390 else staffsep = scan_u(aaa);
391 }
392 if (c=='w') swidth = scan_u(aaa);
393 if (c=='m') lmargin = scan_u(aaa);
394 if (c=='F') strcpy(styf,aaa);
395 if (c=='D') strcpy (styd,aaa);
396 if (c=='g') {
397 if (abbrev(aaa,"shrink", 2)) gmode=G_SHRINK;
398 else if (abbrev(aaa,"stretch",2)) gmode=G_STRETCH;
399 else if (abbrev(aaa,"space", 2)) gmode=G_SPACE;
400 else if (abbrev(aaa,"fill", 2)) gmode=G_FILL;
401 else {
402 printf ("+++ Bad parameter for flag -g: %s\n",aaa);
403 return 1;
404 }
405 }
406 break;
407 }
408 else {
409 printf ("+++ Unknown flag: -%c\n", c);
410 return 1;
411 }
412 m++;
413 }
414 }
415 }
416
417 else {
418 if (strstr(av[i],".fmt")) { /* implict -F */
419 strcpy(styf, av[i]);
420 }
421 else {
422 if (strstr(av[i],".abc") && sel_arg) { /* file if .abc */
423 nsel++;
424 strcpy (sel_str[nsel], "");
425 s_field[nsel]=S_TITLE;
426 if (ninf==0) { /* selector before first file */
427 strcpy(sel_str[nsel],sel_str[nsel-1]);
428 s_field[nsel]=s_field[nsel-1];
429 }
430 sel_arg=0;
431 }
432 if (is_xrefstr(av[i]) && (!sel_arg)) { /* sel if xref numbers */
433 if (i-1 != f_pos) sel_arg=1;
434 }
435
436 if (!sel_arg) { /* this arg is a file name */
437 if (ninf>=MAXINF) {
438 printf ("+++ Too many input files, max is %d\n", MAXINF);
439 return 1;
440 }
441 strcpy (in_file[ninf], av[i]);
442 psel[ninf]=nsel;
443 ninf++;
444 }
445 else { /* this arg is a selector */
446 strcat(sel_str[nsel], av[i]);
447 strcat(sel_str[nsel], " ");
448 }
449 }
450 }
451 i++;
452 }
453
454 return 0;
455 }
456
457 /* ----- alloc_structs ----- */
458 /* Thanks to Henrik Norbeck for this */
459 void alloc_structs ()
460 {
461 int j;
462
463 sym = (struct SYMBOL *)calloc(maxSyms, sizeof(struct SYMBOL));
464 if (sym==NULL) rx("Out of memory","");
465
466 symv = (struct SYMBOL **)calloc(maxVc, sizeof(struct SYMBOL *));
467 if (symv==NULL) rx("Out of memory","");
468
469 for (j=0;j<maxVc;j++) {
470 symv[j] = (struct SYMBOL *)calloc(maxSyms, sizeof(struct SYMBOL));
471 if (symv[j]==NULL) rx("Out of memory","");
472 }
473
474 xp = (struct XPOS *)calloc(maxSyms+1, sizeof(struct XPOS));
475 if (xp==NULL) rx("Out of memory","");
476
477 for (j=0;j<maxSyms+1;j++) {
478 xp[j].p = (int *)calloc(maxVc, sizeof(int));
479 if (xp[j].p==NULL) rx("Out of memory","");
480 }
481
482 voice=(struct VCESPEC *)calloc(maxVc, sizeof(struct VCESPEC));
483 if (voice==NULL) rx("Out of memory","");
484
485 sym_st = (struct SYMBOL **)calloc(maxVc, sizeof(struct SYMBOL *));
486 if (sym_st==NULL) rx("Out of memory","");
487
488 for (j=0;j<maxVc;j++) {
489 sym_st[j] = (struct SYMBOL *)calloc(MAXSYMST, sizeof(struct SYMBOL));
490 if (sym_st[j]==NULL) rx("Out of memory","");
491 }
492
493 nsym_st = (int *)calloc(maxVc, sizeof(int));
494 if (nsym_st==NULL) rx("Out of memory","");
495
496 }
497
498
499 /* ----- set_page_format ----- */
500 int set_page_format ()
501 {
502 int i,j;
503
504 if (pretty==1)
505 set_pretty_format (&cfmt);
506 else if (pretty==2)
507 set_pretty2_format (&cfmt);
508 else
509 set_standard_format (&cfmt);
510
511 i=read_fmt_file ("fonts.fmt", styd, &cfmt);
512 j=0;
513 if (strlen(styf)>0) {
514 strext(styf,styf,"fmt",1);
515 j=read_fmt_file (styf, styd, &cfmt);
516 if (j==0) {
517 printf ("\n+++ Cannot open file: %s\n", styf);
518 return 0;
519 }
520 strcpy(cfmt.name, styf);
521 }
522 if (i || j) printf("\n");
523 ops_into_fmt (&cfmt);
524
525 make_font_list (&cfmt);
526 sfmt=cfmt;
527 dfmt=cfmt;
528 return 1;
529 }
530
531
532 /* ----- tex_str: change string to take care of some tex-style codes --- */
533 /* Puts \ in front of ( and ) in case brackets are not balanced,
534 interprets some TeX-type strings using ISOLatin1 encodings.
535 Returns the length of the string as finally given out on paper.
536 Also returns an estimate of the string width... */
537 int tex_str (str,s,wid)
538 char *str;
539 char s[];
540 float *wid;
541 {
542 char *c;
543 int base,add,n;
544 char t[21];
545 float w;
546
547 c=str;
548 strcpy(s,"");
549 n=0;
550 w=0;
551 while (*c != '\0') {
552
553 if ((*c=='(') || (*c==')')) /* ( ) becomes \( \) */
554 {sprintf(t, "\\%c", *c); strcat(s,t); w+=cwid('('); n++; }
555
556 else if (*c=='\\') { /* backslash sequences */
557 c++;
558 if (*c=='\0') break;
559 add=0; /* accented vowels */
560 if (*c=='`') add=1;
561 if (*c=='\'') add=2;
562 if (*c=='^') add=3;
563 if (*c=='"') add=4;
564 if (add) {
565 c++;
566 base=0;
567 if (*c=='a') { base=340; if (add==4) add=5; }
568 if (*c=='e') base=350;
569 if (*c=='i') base=354;
570 if (*c=='o') { base=362; if (add==4) add=5; }
571 if (*c=='u') base=371;
572 if (*c=='A') { base=300; if (add==4) add=5; }
573 if (*c=='E') base=310;
574 if (*c=='I') base=314;
575 if (*c=='O') { base=322; if (add==4) add=5; }
576 if (*c=='U') base=331;
577 w+=cwid(*c);
578 if (base)
579 {sprintf(t,"\\%d",base+add-1); strcat(s,t); n+=1; }
580 else
581 {sprintf(t,"%c",*c); strcat(s,t); n+=1; }
582 }
583
584 else if (*c==' ') /* \-space */
585 { strcat(s," "); w+=cwid(' '); n++; }
586
587 else if (*c=='O') /* O-slash */
588 { strcat(s,"\\330"); w+=cwid('O'); n++; }
589
590 else if (*c=='o') /* o-slash */
591 { strcat(s,"\\370"); w+=cwid('O'); n++; }
592
593 else if((*c=='s')&&(*(c+1)=='s')) /* sz */
594 { c++; strcat(s,"\\337"); w+=cwid('s'); n++; }
595 else if((*c=='a')&&(*(c+1)=='a')) /* a-ring */
596 { c++; strcat(s,"\\345"); w+=cwid('a'); n++; }
597 else if((*c=='A')&&(*(c+1)=='A')) /* A-ring */
598 { c++; strcat(s,"\\305"); w+=cwid('A'); n++; }
599 else if((*c=='a')&&(*(c+1)=='e')) /* ae */
600 { c++; strcat(s,"\\346"); w+=1.5*cwid('a'); n++; }
601 else if((*c=='A')&&(*(c+1)=='E')) /* AE */
602 { c++; strcat(s,"\\306"); w+=1.5*cwid('A'); n++; }
603
604
605 else if (*c=='c') { /* c-cedilla */
606 c++;
607 w+=cwid(*c);
608 if (*c=='C') { strcat(s,"\\307"); n++; }
609 else if (*c=='c') { strcat(s,"\\347"); n++; }
610 else {sprintf(t,"%c",*c); strcat(s,t); n++; }
611 }
612
613 else if (*c=='~') { /* n-twiddle */
614 c++;
615 w+=cwid(*c);
616 if (*c=='N') { strcat(s,"\\321"); n++; }
617 else if (*c=='n') { strcat(s,"\\361"); n++; }
618 else { sprintf(t,"%c",*c); strcat(s,t); n++; }
619 }
620
621 else /* \-something-else; pass through */
622 {sprintf(t,"\\%c",*c); strcat(s,t); w+=cwid('A'); n++; }
623 }
624
625 else if (*c=='{')
626 ;
627 else if (*c=='}')
628 ;
629
630 else /* other characters: pass though */
631 {
632 sprintf(t,"%c",*c);
633 strcat(s,t); n++;
634 w+=cwid(*c);
635 }
636
637 c++;
638 }
639 *wid = w;
640
641 return n;
642 }
643
644
645 /* ----- put_str: output a string in postscript ----- */
646 void put_str (str)
647 char *str;
648 {
649 char s[801];
650 float w;
651
652 tex_str (str,s,&w);
653 PUT1 ("%s", s);
654 }
655
656 /* ----- set_font ----- */
657 void set_font (fp,font,add_bracket)
658 FILE *fp;
659 struct FONTSPEC font;
660 int add_bracket;
661 {
662 int i,fnum;
663
664 fnum=-1;
665 for (i=0;i<nfontnames;i++) {
666 if (!strcmp(font.name,fontnames[i])) fnum=i;
667 }
668 if (fnum<0) {
669 printf ("\n+++ Font \"%s\" not predefined; using first in list\n",
670 font.name);
671 fnum=0;
672 }
673 PUT3("%.1f %d F%d ", font.size, font.box, fnum)
674 if (add_bracket) PUT0("(")
675 }
676
677 /* ----- set_font_str ----- */
678 void set_font_str (str,font)
679 char str[];
680 struct FONTSPEC font;
681 {
682 int i,fnum;
683
684 fnum=-1;
685 for (i=0;i<nfontnames;i++) {
686 if (!strcmp(font.name,fontnames[i])) fnum=i;
687 }
688 sprintf (str,"%.1f %d F%d ", font.size, font.box, fnum);
689 }
690
691
692 /* ----- check_margin: do horizontal shift if needed ---- */
693 void check_margin (new_posx)
694 float new_posx;
695 {
696 float dif;
697
698 dif=new_posx-posx;
699 if (dif*dif<0.001) return;
700
701 PUT1("%.2f 0 T\n", dif)
702 posx=new_posx;
703 }
704
705
706 /* ----- epsf_title ------ */
707 void epsf_title (title,fnm)
708 char title[],fnm[];
709 {
710 char *p,*q;
711
712 p=title; q=fnm;
713 while (*p != '\0') {
714 if (*p == ' ')
715 *q = '_';
716 else
717 *q = *p;
718 p++; q++;
719 }
720 *q = '\0';
721 }
722
723 /* ----- close_output_file ------ */
724 void close_output_file ()
725 {
726 int m;
727
728 if (!file_open) return;
729
730 if (interactive) printf ("(close %s)\n", outfnam);
731
732 close_page(fout);
733 close_ps (fout);
734 fclose (fout);
735 if (tunenum==0)
736 printf ("+++ Warning: no tunes written to output file\n");
737 m=get_file_size (outfnam);
738 printf ("Output written on %s (%d page%s, %d title%s, %d byte%s)\n",
739 outfnam,
740 pagenum, pagenum==1 ? "" : "s",
741 tunenum, tunenum==1 ? "" : "s",
742 m, m==1 ? "" : "s");
743 file_open=0;
744 file_initialized=0;
745
746 }
747
748
749 /* ----- open_output_file ------ */
750 void open_output_file (fnam,tstr)
751 char fnam[],tstr[];
752 {
753
754 if (!strcmp(fnam,outfnam)) return;
755
756 if (file_open) close_output_file ();
757
758 if (interactive) printf ("(open %s)\n", fnam);
759 strcpy (outfnam, fnam);
760 if ((fout = fopen (outfnam,"w")) == NULL)
761 rx ("Cannot open output file ", outf);
762 pagenum=0;
763 tunenum=tnum1=tnum2=0;
764 file_open=1;
765 file_initialized=0;
766
767 }
768
769
770
771 /* ----- open_index_file ------- */
772 void open_index_file (fnam)
773 char fnam[];
774 {
775 if (vb>=8) printf("Open index file \"%s\"\n", fnam);
776 if ((findex = fopen (fnam,"w")) == NULL)
777 rx ("Cannot open index file: ", fnam);
778
779 index_initialized=0;
780
781 }
782
783 /* ----- close_index_file ------- */
784 void close_index_file ()
785 {
786
787 if (vb>=8) printf("Close index file\n");
788
789 close_index_page (findex);
790
791 fclose (findex);
792
793 }
794
795 /* ----- add_to_text_block ----- */
796 void add_to_text_block (ln,add_final_nl)
797 char ln[];
798 int add_final_nl;
799 {
800 char *c,*a;
801 char word[81];
802 int nt,nl;
803
804 nt=ntxt;
805 c=ln;
806
807 for (;;) {
808 while (*c==' ') c++;
809 if (*c=='\0') break;
810 a=word;
811 while ((*c!=' ')&&(*c!='\0')&&(*c!='\n')) {
812 nl=0;
813 if ((*c=='\\')&&(*(c+1)=='\\')) {
814 nl=1;
815 c+=2;
816 break;
817 }
818 *a=*c;
819 c++;
820 a++;
821
822 }
823 *a='\0';
824 if (strlen(word)>MAXWLEN) {
825 word[MAXWLEN-1]='\0';
826 printf ("+++ Insanely long word truncated to %d chars: %s\n",
827 MAXWLEN-1,word);
828 }
829 if (nt>=MAXNTEXT) {
830 printf ("\n+++ Line %d: %s\n", linenum,ln);
831 rx("Text overflow; increase MAXNTEXT and recompile.","");
832 }
833 if (strlen(word)>0) {
834 strcpy(txt[nt],word);
835 nt++;
836 }
837 if (nl) {
838 strcpy(txt[nt],"$$NL$$");
839 nt++;
840 }
841 }
842 if (add_final_nl) {
843 strcpy(txt[nt],"$$NL$$");
844 nt++;
845 }
846
847 ntxt=nt;
848
849 }
850
851
852 /* ----- write_text_block ----- */
853 void write_text_block (fp,job)
854 FILE *fp;
855 int job;
856 {
857 int i,i1,i2,ntline,nc,mc,nbreak;
858 float textwidth,ftline,ftline0,swfac,baseskip,parskip;
859 float wwidth,wtot,spw;
860 char str[81];
861
862 if (ntxt<=0) return;
863
864 baseskip = cfmt.textfont.size * cfmt.lineskipfac;
865 parskip = cfmt.textfont.size * cfmt.parskipfac;
866 set_font_str (page_init,cfmt.textfont);
867
868 /* estimate text widths.. ok for T-R, wild guess for other fonts */
869 swfac=1.0;
870 if (strstr(cfmt.textfont.name,"Times-Roman")) swfac=1.00;
871 if (strstr(cfmt.textfont.name,"Times-Bold")) swfac=1.05;
872 if (strstr(cfmt.textfont.name,"Helvetica")) swfac=1.10;
873 if (strstr(cfmt.textfont.name,"Helvetica-Bold")) swfac=1.15;
874 if (strstr(cfmt.textfont.name,"Palatino")) swfac=1.10;
875 swfac=1.0;
876 spw=cwid(' ');
877 PUT1("/LF {0 %.1f rmoveto} bind def\n",-baseskip)
878
879 /* output by pieces, separate at newline token */
880 i1=0;
881 while (i1<ntxt) {
882 i2=-1;
883 for (i=i1;i<ntxt;i++) if(!strcmp(txt[i],"$$NL$$")) {i2=i; break; }
884 if (i2==-1) i2=ntxt;
885 bskip(baseskip);
886
887 if (job==OBEYLINES) {
888 PUT0("0 0 M (")
889 for (i=i1;i<i2;i++) {
890 tex_str(txt[i],str,&wwidth);
891 PUT1("%s ",str);
892 }
893 PUT0(") rshow\n")
894 }
895
896 else if (job==OBEYCENTER) {
897 PUT1("%.1f 0 M (",cfmt.staffwidth/2)
898 for (i=i1;i<i2;i++) {
899 tex_str(txt[i],str,&wwidth);
900 PUT1("%s",str)
901 if (i<i2-1) PUT0(" ")
902 }
903 PUT0(") cshow\n")
904 }
905
906 else {
907 PUT0("0 0 M mark\n")
908 nc=0;
909 mc=-1;
910 wtot=-spw;
911 for (i=i2-1;i>=i1;i--) {
912 mc+=tex_str(txt[i],str,&wwidth)+1;
913 wtot+=wwidth+spw;
914 nc+=strlen(str)+2;
915 if (nc>=72) {nc=0; PUT0("\n") }
916 PUT1 ("(%s)",str);
917 }
918 if (job==RAGGED)
919 PUT1(" %.1f P1\n",cfmt.staffwidth)
920 else
921 PUT1(" %.1f P2\n",cfmt.staffwidth)
922 /* first estimate: (total textwidth)/(available width) */
923 textwidth=wtot*swfac*cfmt.textfont.size;
924 if (strstr(cfmt.textfont.name,"Courier"))
925 textwidth=0.60*mc*cfmt.textfont.size;
926 ftline0=textwidth/cfmt.staffwidth;
927 /* revised estimate: assume some chars lost at each line end */
928 nbreak=ftline0;
929 textwidth=textwidth+5*nbreak*cwid('a')*swfac*cfmt.textfont.size;
930 ftline=textwidth/cfmt.staffwidth;
931 ntline=ftline+1.0;
932 if (vb>=10)
933 printf("first estimate %.2f, revised %.2f\n", ftline0,ftline);
934 if (vb>=10)
935 printf("Output %d word%s, about %.2f lines (fac %.2f)\n",
936 i2-i1, i2-i1==1?"":"s", ftline,swfac);
937 bskip((ntline-1)*baseskip);
938 }
939
940 buffer_eob (fp);
941 /* next line to allow pagebreak after each text "line" */
942 /* if (!epsf && !within_tune) write_buffer(fp); */
943 i1=i2+1;
944 }
945 bskip(parskip);
946 buffer_eob (fp);
947 /* next line to allow pagebreak after each paragraph */
948 if (!epsf && !within_tune) write_buffer(fp);
949 strcpy (page_init,"");
950 return;
951 }
952
953
954
955 /* ----- put_words ------- */
956 void put_words (fp)
957 FILE *fp;
958 {
959 int i,nw,n;
960 char str[81];
961 char *p,*q;
962
963 set_font (fp,cfmt.wordsfont, 0);
964 set_font_str (page_init,cfmt.wordsfont);
965
966 n=0;
967 for (i=0;i<ntext;i++) if (text_type[i]==TEXT_W) n++;
968 if (n==0) return;
969
970 bskip(cfmt.wordsspace);
971 for (i=0;i<ntext;i++) {
972 if (text_type[i]==TEXT_W) {
973 bskip(cfmt.lineskipfac*cfmt.wordsfont.size);
974 p=&text[i][0];
975 q=&str[0];
976 if (isdig(text[i][0])) {
977 while (*p != '\0') {
978 *q=*p;
979 q++;
980 p++;
981 if (*p==' ') break;
982 if (*(p-1)==':') break;
983 if (*(p-1)=='.') break;
984 }
985 if (*p==' ') p++;
986 }
987 *q='\0';
988
989 /* permit page break at empty lines or stanza start */
990 nw=nwords(text[i]);
991 if ((nw==0) || (strlen(str)>0)) buffer_eob(fp);
992
993 if (nw>0) {
994 if (strlen(str)>0) {
995 PUT0("45 0 M (")
996 put_str (str);
997 PUT0(") lshow\n")
998 }
999 if (strlen(p)>0) {
1000 PUT0("50 0 M (")
1001 put_str (p);
1002 PUT0(") rshow\n")
1003 }
1004 }
1005 }
1006 }
1007
1008 buffer_eob (fp);
1009 strcpy (page_init,"");
1010
1011 }
1012
1013 /* ----- put_text ------- */
1014 void put_text (fp, type, str)
1015 FILE *fp;
1016 int type;
1017 char str[];
1018 {
1019 int i,n;
1020 float baseskip,parskip;
1021
1022 n=0;
1023 for (i=0;i<ntext;i++) if (text_type[i]==type) n++;
1024 if (n==0) return;
1025
1026 baseskip = cfmt.textfont.size * cfmt.lineskipfac;
1027 parskip = cfmt.textfont.size * cfmt.parskipfac;
1028 PUT0("0 0 M\n")
1029 ntxt=0;
1030 add_to_text_block(str,0);
1031 for (i=0;i<ntext;i++) {
1032 if (text_type[i]==type) add_to_text_block(text[i],1);
1033 }
1034 write_text_block (fp,RAGGED);
1035 buffer_eob (fp);
1036
1037 }
1038
1039 /* ----- put_history ------- */
1040 void put_history (fp)
1041 FILE *fp;
1042 {
1043 int i,ok;
1044 float baseskip,parskip;
1045
1046 set_font (fp, cfmt.textfont,0);
1047 set_font_str (page_init,cfmt.textfont);
1048 baseskip = cfmt.textfont.size * cfmt.lineskipfac;
1049 parskip = cfmt.textfont.size * cfmt.parskipfac;
1050
1051 bskip(cfmt.textspace);
1052
1053 if (strlen(info.rhyth)>0) {
1054 bskip(baseskip);
1055 PUT0("0 0 M (Rhythm: ")
1056 put_str (info.rhyth);
1057 PUT0(") show\n")
1058 bskip(parskip);
1059 }
1060
1061 if (strlen(info.book)>0) {
1062 bskip(0.5*CM);
1063 PUT0("0 0 M (Book: ")
1064 put_str (info.book);
1065 PUT0(") show\n")
1066 bskip(parskip);
1067 }
1068
1069 if (strlen(info.src)>0) {
1070 bskip(0.5*CM);
1071 PUT0("0 0 M (Source: ")
1072 put_str (info.src);
1073 PUT0(") show\n")
1074 bskip(parskip);
1075 }
1076
1077 put_text (fp, TEXT_D, "Discography: ");
1078 put_text (fp, TEXT_N, "Notes: ");
1079 put_text (fp, TEXT_Z, "Transcription: ");
1080
1081 ok=0;
1082 for (i=0;i<ntext;i++) {
1083 if (text_type[i]==TEXT_H) {
1084 bskip(0.5*CM);
1085 PUT0("0 0 M (")
1086 put_str (text[i]);
1087 PUT0(") show\n")
1088 ok=1;
1089 }
1090 }
1091 if (ok) bskip(parskip);
1092 buffer_eob (fp);
1093 strcpy (page_init,"");
1094
1095 }
1096
1097
1098 /* ----- write_inside_title ----- */
1099 void write_inside_title (fp)
1100 FILE *fp;
1101 {
1102 char t[201];
1103
1104 if (numtitle==1) strcpy (t,info.title);
1105 else if (numtitle==2) strcpy (t,info.title2);
1106 else if (numtitle==3) strcpy (t,info.title3);
1107 if (vb>15) printf ("write inside title <%s>\n", t);
1108 if (strlen(t)==0) return;
1109
1110 bskip (cfmt.subtitlefont.size+0.2*CM);
1111 set_font (fp, cfmt.subtitlefont, 0);
1112
1113 if (cfmt.titlecaps) cap_str(t);
1114 PUT0(" (")
1115 put_str (t);
1116 if (cfmt.titleleft) PUT0(") 0 0 M rshow\n")
1117 else PUT1(") %.1f 0 M cshow\n", cfmt.staffwidth/2)
1118 bskip (cfmt.musicspace+0.2*CM);
1119
1120 }
1121
1122
1123 /* ----- write_tunetop ----- */
1124 void write_tunetop(fp)
1125 FILE *fp;
1126 {
1127
1128 PUT2("\n\n%% --- tune %d %s\n", tunenum+1, info.title)
1129 if (!epsf) bskip (cfmt.topspace);
1130 }
1131
1132
1133 /* ----- write_tempo ----- */
1134 void write_tempo(fp,tempo,meter)
1135 FILE *fp;
1136 char tempo[];
1137 struct METERSTR meter;
1138 {
1139 char *r, *q;
1140 char text[STRL];
1141 int top,bot,value,len,i,err,fac,dig,div,rc;
1142 struct SYMBOL s;
1143 float stem,dotx,doty,sc,dx;
1144
1145 if (vb>15) printf ("write tempo <%s>\n", info.tempo);
1146 r=tempo;
1147 p0=tempo;
1148 set_font (fp,cfmt.tempofont,0);
1149 PUT0(" 18 0 M\n")
1150
1151 for (;;) {
1152
1153 while (*r==' ') r++; /* skip blanks */
1154 if (*r=='\0') break;
1155
1156 if (*r=='"') { /* write string */
1157 r++;
1158 q=text;
1159 while (*r!='"' && *r!='\0') { *q=*r; r++; q++; }
1160 if (*r=='"') r++;
1161 *q='\0';
1162 if (strlen(text)>0) {
1163 PUT0("6 0 rmoveto (")
1164 put_str (text);
1165 PUT0(") rshow 12 0 \n")
1166 }
1167 }
1168
1169 else { /* write tempo denotation */
1170 q=text;
1171 while (*r!=' ' && *r!='\0') { *q=*r; r++; q++; }
1172 *q='\0';
1173 q=text;
1174
1175 len=QUARTER;
1176 value=0;
1177 err=0;
1178 if (strchr(q,'=')) {
1179 if ((*q=='C') || (*q=='c')) {
1180 q++;
1181
1182 len=meter.dlen;
1183 div=0;
1184 if (*q=='/') { div=1; q++; }
1185 fac=0;
1186 while (isdig(*q)) { dig=*q-'0'; fac=10*fac+dig; q++; }
1187
1188 if (div) {
1189 if (fac==0) fac=2;
1190 if (len%fac) printf ("Bad length divisor in tempo: %s", text);
1191 len=len/fac;
1192 }
1193 else
1194 if (fac>0) len=len*fac;
1195 if (*q!='=') err=1;
1196 q++;
1197 if (!isdig(*q)) err=1;
1198 sscanf(q,"%d", &value);
1199 }
1200 else if (isdig(*q)) {
1201 sscanf(q,"%d/%d=%d", &top,&bot,&value);
1202 len=(BASE*top)/bot;
1203 }
1204 else err=1;
1205 }
1206 else {
1207 if (isdig(*q))
1208 sscanf(q,"%d", &value);
1209 else err=1;
1210 }
1211
1212 s.len=len;
1213 rc = idfy_note (&s);
1214 if (rc) err=1;
1215 if (err) /* draw note=value */
1216 printf("\n+++ invalid tempo specifier: %s\n", text);
1217 else {
1218 sc=0.55*cfmt.tempofont.size/10.0;
1219 PUT2("gsave %.2f %.2f scale 15 3 rmoveto currentpoint\n", sc,sc)
1220 if (s.head==H_OVAL) PUT0("HD")
1221 if (s.head==H_EMPTY) PUT0("Hd")
1222 if (s.head==H_FULL) PUT0("hd")
1223 dx=4.0;
1224 if (s.dots) {
1225 dotx=8; doty=0;
1226 if (s.flags>0) dotx=dotx+4;
1227 if (s.head==H_EMPTY) dotx=dotx+1;
1228 if (s.head==H_OVAL) dotx=dotx+2;
1229 for (i=0;i<s.dots;i++) {
1230 PUT2(" %.1f %.1f dt", dotx, doty)
1231 dx=dotx;
1232 dotx=dotx+3.5;
1233 }
1234 }
1235 stem=16.0;
1236 if (s.flags>1) stem=stem+3*(s.flags-1);
1237 if (s.len<WHOLE) PUT1(" %.1f su",stem)
1238 if (s.flags>0) PUT2(" %.1f f%du",stem,s.flags)
1239 if ((s.flags>0) && (dx<6.0)) dx=6.0;
1240 dx=(dx+18)*sc;
1241 PUT2(" grestore %.2f 0 rmoveto ( = %d) rshow\n", dx,value)
1242 }
1243 }
1244 }
1245 }
1246
1247
1248 /* ----- write_inside_tempo ----- */
1249 void write_inside_tempo (fp)
1250 FILE *fp;
1251 {
1252
1253 bskip (cfmt.partsfont.size);
1254 write_tempo(fp,info.tempo,default_meter);
1255 bskip (0.1*CM);
1256 }
1257
1258 /* ----- write_heading ----- */
1259 void write_heading (fp)
1260 FILE *fp;
1261 {
1262 float lwidth,down1,down2;
1263 int i,ncl;
1264 char t[201];
1265
1266 lwidth=cfmt.staffwidth;
1267
1268 /* write the main title */
1269 bskip (cfmt.titlefont.size+cfmt.titlespace);
1270 set_font (fp,cfmt.titlefont,1);
1271 if (cfmt.withxrefs) PUT1("%d. ", xrefnum)
1272 strcpy (t,info.title);
1273 if (cfmt.titlecaps) cap_str(t);
1274 put_str (t);
1275 if (cfmt.titleleft) PUT0(") 0 0 M rshow\n")
1276 else PUT1(") %.1f 0 M cshow\n", lwidth/2)
1277
1278 /* write second title */
1279 if (numtitle>=2) {
1280 bskip (cfmt.subtitlespace+cfmt.subtitlefont.size);
1281 set_font (fp,cfmt.subtitlefont,1);
1282 strcpy (t,info.title2);
1283 if (cfmt.titlecaps) cap_str(t);
1284 put_str (t);
1285 if (cfmt.titleleft) PUT0(") 0 0 M rshow\n")
1286 else PUT1(") %.1f 0 M cshow\n", lwidth/2)
1287 }
1288
1289 /* write third title */
1290 if (numtitle>=3) {
1291 bskip (cfmt.subtitlespace+cfmt.subtitlefont.size);
1292 set_font (fp,cfmt.subtitlefont,1);
1293 strcpy (t,info.title3);
1294 if (cfmt.titlecaps) cap_str(t);
1295 put_str (t);
1296 if (cfmt.titleleft) PUT0(") 0 0 M rshow\n")
1297 else PUT1(") %.1f 0 M cshow\n", lwidth/2)
1298 }
1299
1300 /* write composer, origin */
1301 if ((info.ncomp>0) || (strlen(info.orig)>0)) {
1302 set_font (fp,cfmt.composerfont,0);
1303 bskip(cfmt.composerspace);
1304 ncl=info.ncomp;
1305 if ((strlen(info.orig)>0) && (ncl<1)) ncl=1;
1306 for (i=0;i<ncl;i++) {
1307 bskip(cfmt.composerfont.size);
1308 PUT1("%.1f 0 M (", lwidth)
1309 put_str (info.comp[i]);
1310 if ((i==ncl-1)&&(strlen(info.orig)>0)) {
1311 put_str (" (");
1312 put_str (info.orig);
1313 put_str (")");
1314 }
1315 PUT0 (") lshow\n");
1316 }
1317 down1=cfmt.composerspace+cfmt.musicspace+ncl*cfmt.composerfont.size;
1318 }
1319 else {
1320 bskip(cfmt.composerfont.size+cfmt.composerspace);
1321 down1=cfmt.composerspace+cfmt.musicspace+cfmt.composerfont.size;
1322 }
1323 bskip (cfmt.musicspace);
1324
1325 /* decide whether we need extra shift for parts and tempo */
1326 down2=cfmt.composerspace+cfmt.musicspace;
1327 if (strlen(info.parts)>0) down2=down2+cfmt.partsspace+cfmt.partsfont.size;
1328 if (strlen(info.tempo)>0) down2=down2+cfmt.partsspace+cfmt.partsfont.size;
1329 if (down2>down1) bskip (down2-down1);
1330
1331 /* write tempo and parts */
1332 if (strlen(info.parts)>0 || strlen(info.tempo)>0) {
1333
1334 if (strlen(info.tempo)>0) {
1335 bskip (-0.2*CM);
1336 PUT1 (" %.2f 0 T ", cfmt.indent*cfmt.scale)
1337 write_tempo(fp, info.tempo, default_meter);
1338 PUT1 (" %.2f 0 T ", -cfmt.indent*cfmt.scale)
1339 bskip (-cfmt.tempofont.size);
1340 }
1341
1342 if (strlen(info.parts)>0) {
1343 bskip (-cfmt.partsspace);
1344 set_font (fp,cfmt.partsfont,0);
1345 PUT0("0 0 M (")
1346 put_str (info.parts);
1347 PUT0(") rshow\n")
1348 bskip (cfmt.partsspace);
1349 }
1350
1351 if (strlen(info.tempo)>0) bskip (cfmt.tempofont.size+0.3*CM);
1352
1353 }
1354
1355
1356 }
1357
1358 /* ----- write_parts ----- */
1359 void write_parts (fp)
1360 FILE *fp;
1361 {
1362 if (strlen(info.parts)>0) {
1363 bskip (cfmt.partsfont.size);
1364 set_font (fp, cfmt.partsfont,0);
1365 PUT0("0 0 M (")
1366 put_str (info.parts);
1367 PUT0(") rshow\n")
1368 bskip(cfmt.partsspace);
1369 }
1370 }
1371
1372